Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / beast / core / impl / file_stdio.ipp
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/config/workaround.hpp>
15 #include <boost/core/exchange.hpp>
16 #include <limits>
17
18 namespace boost {
19 namespace beast {
20
21 file_stdio::
22 ~file_stdio()
23 {
24     if(f_)
25         fclose(f_);
26 }
27
28 file_stdio::
29 file_stdio(file_stdio&& other)
30     : f_(boost::exchange(other.f_, nullptr))
31 {
32 }
33
34 file_stdio&
35 file_stdio::
36 operator=(file_stdio&& other)
37 {
38     if(&other == this)
39         return *this;
40     if(f_)
41         fclose(f_);
42     f_ = other.f_;
43     other.f_ = nullptr;
44     return *this;
45 }
46
47 void
48 file_stdio::
49 native_handle(FILE* f)
50 {
51     if(f_)
52         fclose(f_);
53     f_ = f;
54 }
55
56 void
57 file_stdio::
58 close(error_code& ec)
59 {
60     if(f_)
61     {
62         int failed = fclose(f_);
63         f_ = nullptr;
64         if(failed)
65         {
66             ec.assign(errno, generic_category());
67             return;
68         }
69     }
70     ec = {};
71 }
72
73 void
74 file_stdio::
75 open(char const* path, file_mode mode, error_code& ec)
76 {
77     if(f_)
78     {
79         fclose(f_);
80         f_ = nullptr;
81     }
82     char const* s;
83     switch(mode)
84     {
85     default:
86     case file_mode::read:
87         s = "rb";
88         break;
89
90     case file_mode::scan:
91     #ifdef BOOST_MSVC
92         s = "rbS";
93     #else
94         s = "rb";
95     #endif
96         break;
97
98     case file_mode::write:
99         s = "wb+";
100         break;
101
102     case file_mode::write_new:
103     {
104 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
105         FILE* f0;
106         auto const ev = ::fopen_s(&f0, path, "rb");
107         if(! ev)
108         {
109             std::fclose(f0);
110             ec = make_error_code(errc::file_exists);
111             return;
112         }
113         else if(ev !=
114             errc::no_such_file_or_directory)
115         {
116             ec.assign(ev, generic_category());
117             return;
118         }
119         s = "wb";
120 #else
121         
122         s = "wbx";
123 #endif
124         break;
125     }
126
127     case file_mode::write_existing:
128         s = "rb+";
129         break;
130
131     case file_mode::append:
132         s = "ab";
133         break;
134
135     case file_mode::append_existing:
136     {
137 #ifdef BOOST_MSVC
138         FILE* f0;
139         auto const ev =
140             ::fopen_s(&f0, path, "rb+");
141         if(ev)
142         {
143             ec.assign(ev, generic_category());
144             return;
145         }
146 #else
147         auto const f0 =
148             std::fopen(path, "rb+");
149         if(! f0)
150         {
151             ec.assign(errno, generic_category());
152             return;
153         }
154 #endif
155         std::fclose(f0);
156         s = "ab";
157         break;
158     }
159     }
160
161 #ifdef BOOST_MSVC
162     auto const ev = ::fopen_s(&f_, path, s);
163     if(ev)
164     {
165         f_ = nullptr;
166         ec.assign(ev, generic_category());
167         return;
168     }
169 #else
170     f_ = std::fopen(path, s);
171     if(! f_)
172     {
173         ec.assign(errno, generic_category());
174         return;
175     }
176 #endif
177     ec = {};
178 }
179
180 std::uint64_t
181 file_stdio::
182 size(error_code& ec) const
183 {
184     if(! f_)
185     {
186         ec = make_error_code(errc::bad_file_descriptor);
187         return 0;
188     }
189     long pos = std::ftell(f_);
190     if(pos == -1L)
191     {
192         ec.assign(errno, generic_category());
193         return 0;
194     }
195     int result = std::fseek(f_, 0, SEEK_END);
196     if(result != 0)
197     {
198         ec.assign(errno, generic_category());
199         return 0;
200     }
201     long size = std::ftell(f_);
202     if(size == -1L)
203     {
204         ec.assign(errno, generic_category());
205         std::fseek(f_, pos, SEEK_SET);
206         return 0;
207     }
208     result = std::fseek(f_, pos, SEEK_SET);
209     if(result != 0)
210         ec.assign(errno, generic_category());
211     else
212         ec = {};
213     return size;
214 }
215
216 std::uint64_t
217 file_stdio::
218 pos(error_code& ec) const
219 {
220     if(! f_)
221     {
222         ec = make_error_code(errc::bad_file_descriptor);
223         return 0;
224     }
225     long pos = std::ftell(f_);
226     if(pos == -1L)
227     {
228         ec.assign(errno, generic_category());
229         return 0;
230     }
231     ec = {};
232     return pos;
233 }
234
235 void
236 file_stdio::
237 seek(std::uint64_t offset, error_code& ec)
238 {
239     if(! f_)
240     {
241         ec = make_error_code(errc::bad_file_descriptor);
242         return;
243     }
244     if(offset > static_cast<std::uint64_t>(std::numeric_limits<long>::max()))
245     {
246         ec = make_error_code(errc::invalid_seek);
247         return;
248     }
249     int result = std::fseek(f_,
250         static_cast<long>(offset), SEEK_SET);
251     if(result != 0)
252         ec.assign(errno, generic_category());
253     else
254         ec = {};
255 }
256
257 std::size_t
258 file_stdio::
259 read(void* buffer, std::size_t n, error_code& ec) const
260 {
261     if(! f_)
262     {
263         ec = make_error_code(errc::bad_file_descriptor);
264         return 0;
265     }
266     auto nread = std::fread(buffer, 1, n, f_);
267     if(std::ferror(f_))
268     {
269         ec.assign(errno, generic_category());
270         return 0;
271     }
272     return nread;
273 }
274
275 std::size_t
276 file_stdio::
277 write(void const* buffer, std::size_t n, error_code& ec)
278 {
279     if(! f_)
280     {
281         ec = make_error_code(errc::bad_file_descriptor);
282         return 0;
283     }
284     auto nwritten = std::fwrite(buffer, 1, n, f_);
285     if(std::ferror(f_))
286     {
287         ec.assign(errno, generic_category());
288         return 0;
289     }
290     return nwritten;
291 }
292
293 } // beast
294 } // boost
295
296 #endif