src/detail/file_stdio.cpp

84.9% Lines (107/126) 100.0% Functions (11/11)
src/detail/file_stdio.cpp
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2022 Vinnie Falco ([email protected])
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
8 //
9
10 #include "src/detail/win32_unicode_path.hpp"
11 #include <boost/http/detail/file_stdio.hpp>
12 #include <boost/http/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 {
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 ec.assign(errno,
71 system::generic_category());
72 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 ec.assign(errno,
238 system::generic_category());
239 return 0;
240 }
241 1 int result = std::fseek(f_, 0, SEEK_END);
242 1 if(result != 0)
243 {
244 ec.assign(errno,
245 system::generic_category());
246 return 0;
247 }
248 1 long size = std::ftell(f_);
249 1 if(size == -1L)
250 {
251 ec.assign(errno,
252 system::generic_category());
253 std::fseek(f_, pos, SEEK_SET);
254 return 0;
255 }
256 1 result = std::fseek(f_, pos, SEEK_SET);
257 1 if(result != 0)
258 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 ec.assign(errno,
280 system::generic_category());
281 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 ec = make_error_code(
301 system::errc::invalid_seek);
302 return;
303 }
304 1 int result = std::fseek(f_,
305 static_cast<long>(offset), SEEK_SET);
306 1 if(result != 0)
307 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 ec.assign(errno,
328 system::generic_category());
329 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 ec.assign(errno,
349 system::generic_category());
350 return 0;
351 }
352 4 return nwritten;
353 }
354
355 } // detail
356 } // http
357 } // boost
358