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