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