• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
11#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
12
13#include <boost/beast/core/file_stdio.hpp>
14#include <boost/beast/core/detail/win32_unicode_path.hpp>
15#include <boost/config/workaround.hpp>
16#include <boost/core/exchange.hpp>
17#include <limits>
18
19namespace boost {
20namespace beast {
21
22file_stdio::
23~file_stdio()
24{
25    if(f_)
26        fclose(f_);
27}
28
29file_stdio::
30file_stdio(file_stdio&& other)
31    : f_(boost::exchange(other.f_, nullptr))
32{
33}
34
35file_stdio&
36file_stdio::
37operator=(file_stdio&& other)
38{
39    if(&other == this)
40        return *this;
41    if(f_)
42        fclose(f_);
43    f_ = other.f_;
44    other.f_ = nullptr;
45    return *this;
46}
47
48void
49file_stdio::
50native_handle(std::FILE* f)
51{
52    if(f_)
53        fclose(f_);
54    f_ = f;
55}
56
57void
58file_stdio::
59close(error_code& ec)
60{
61    if(f_)
62    {
63        int failed = fclose(f_);
64        f_ = nullptr;
65        if(failed)
66        {
67            ec.assign(errno, generic_category());
68            return;
69        }
70    }
71    ec = {};
72}
73
74void
75file_stdio::
76open(char const* path, file_mode mode, error_code& ec)
77{
78    if(f_)
79    {
80        fclose(f_);
81        f_ = nullptr;
82    }
83    ec = {};
84#ifdef BOOST_MSVC
85    boost::winapi::WCHAR_ const* s;
86    detail::win32_unicode_path unicode_path(path, ec);
87    if (ec)
88        return;
89#else
90    char const* s;
91#endif
92    switch(mode)
93    {
94    default:
95    case file_mode::read:
96    #ifdef BOOST_MSVC
97        s = L"rb";
98    #else
99        s = "rb";
100    #endif
101        break;
102
103    case file_mode::scan:
104    #ifdef BOOST_MSVC
105        s = L"rbS";
106    #else
107        s = "rb";
108    #endif
109        break;
110
111    case file_mode::write:
112    #ifdef BOOST_MSVC
113        s = L"wb+";
114    #else
115        s = "wb+";
116    #endif
117        break;
118
119    case file_mode::write_new:
120    {
121#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
122        std::FILE* f0;
123        auto const ev = ::_wfopen_s(&f0, unicode_path.c_str(), L"rb");
124        if(! ev)
125        {
126            std::fclose(f0);
127            ec = make_error_code(errc::file_exists);
128            return;
129        }
130        else if(ev !=
131            errc::no_such_file_or_directory)
132        {
133            ec.assign(ev, generic_category());
134            return;
135        }
136        s = L"wb";
137#elif defined(BOOST_MSVC)
138        s = L"wbx";
139#else
140        s = "wbx";
141#endif
142        break;
143    }
144
145    case file_mode::write_existing:
146    #ifdef BOOST_MSVC
147        s = L"rb+";
148    #else
149        s = "rb+";
150    #endif
151        break;
152
153    case file_mode::append:
154    #ifdef BOOST_MSVC
155        s = L"ab";
156    #else
157        s = "ab";
158    #endif
159        break;
160
161    case file_mode::append_existing:
162    {
163#ifdef BOOST_MSVC
164        std::FILE* f0;
165        auto const ev =
166            ::_wfopen_s(&f0, unicode_path.c_str(), L"rb+");
167        if(ev)
168        {
169            ec.assign(ev, generic_category());
170            return;
171        }
172#else
173        auto const f0 =
174            std::fopen(path, "rb+");
175        if(! f0)
176        {
177            ec.assign(errno, generic_category());
178            return;
179        }
180#endif
181        std::fclose(f0);
182    #ifdef BOOST_MSVC
183        s = L"ab";
184    #else
185        s = "ab";
186    #endif
187        break;
188    }
189    }
190
191#ifdef BOOST_MSVC
192    auto const ev = ::_wfopen_s(&f_, unicode_path.c_str(), s);
193    if(ev)
194    {
195        f_ = nullptr;
196        ec.assign(ev, generic_category());
197        return;
198    }
199#else
200    f_ = std::fopen(path, s);
201    if(! f_)
202    {
203        ec.assign(errno, generic_category());
204        return;
205    }
206#endif
207}
208
209std::uint64_t
210file_stdio::
211size(error_code& ec) const
212{
213    if(! f_)
214    {
215        ec = make_error_code(errc::bad_file_descriptor);
216        return 0;
217    }
218    long pos = std::ftell(f_);
219    if(pos == -1L)
220    {
221        ec.assign(errno, generic_category());
222        return 0;
223    }
224    int result = std::fseek(f_, 0, SEEK_END);
225    if(result != 0)
226    {
227        ec.assign(errno, generic_category());
228        return 0;
229    }
230    long size = std::ftell(f_);
231    if(size == -1L)
232    {
233        ec.assign(errno, generic_category());
234        std::fseek(f_, pos, SEEK_SET);
235        return 0;
236    }
237    result = std::fseek(f_, pos, SEEK_SET);
238    if(result != 0)
239        ec.assign(errno, generic_category());
240    else
241        ec = {};
242    return size;
243}
244
245std::uint64_t
246file_stdio::
247pos(error_code& ec) const
248{
249    if(! f_)
250    {
251        ec = make_error_code(errc::bad_file_descriptor);
252        return 0;
253    }
254    long pos = std::ftell(f_);
255    if(pos == -1L)
256    {
257        ec.assign(errno, generic_category());
258        return 0;
259    }
260    ec = {};
261    return pos;
262}
263
264void
265file_stdio::
266seek(std::uint64_t offset, error_code& ec)
267{
268    if(! f_)
269    {
270        ec = make_error_code(errc::bad_file_descriptor);
271        return;
272    }
273    if(offset > static_cast<std::uint64_t>((std::numeric_limits<long>::max)()))
274    {
275        ec = make_error_code(errc::invalid_seek);
276        return;
277    }
278    int result = std::fseek(f_,
279        static_cast<long>(offset), SEEK_SET);
280    if(result != 0)
281        ec.assign(errno, generic_category());
282    else
283        ec = {};
284}
285
286std::size_t
287file_stdio::
288read(void* buffer, std::size_t n, error_code& ec) const
289{
290    if(! f_)
291    {
292        ec = make_error_code(errc::bad_file_descriptor);
293        return 0;
294    }
295    auto nread = std::fread(buffer, 1, n, f_);
296    if(std::ferror(f_))
297    {
298        ec.assign(errno, generic_category());
299        return 0;
300    }
301    return nread;
302}
303
304std::size_t
305file_stdio::
306write(void const* buffer, std::size_t n, error_code& ec)
307{
308    if(! f_)
309    {
310        ec = make_error_code(errc::bad_file_descriptor);
311        return 0;
312    }
313    auto nwritten = std::fwrite(buffer, 1, n, f_);
314    if(std::ferror(f_))
315    {
316        ec.assign(errno, generic_category());
317        return 0;
318    }
319    return nwritten;
320}
321
322} // beast
323} // boost
324
325#endif
326