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