src/detail/file_stdio.cpp

84.9% Lines (107/126) 100.0% List of functions (11/11)
file_stdio.cpp
f(x) Functions (11)
Line TLA Hits 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
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 23x file_stdio::
23 ~file_stdio()
24 {
25 23x if(f_)
26 11x fclose(f_);
27 23x }
28
29 1x file_stdio::
30 file_stdio(
31 1x file_stdio&& other) noexcept
32 1x : f_(boost::exchange(other.f_, nullptr))
33 {
34 1x }
35
36 file_stdio&
37 3x file_stdio::
38 operator=(
39 file_stdio&& other) noexcept
40 {
41 3x if(&other == this)
42 1x return *this;
43 2x if(f_)
44 1x fclose(f_);
45 2x f_ = other.f_;
46 2x other.f_ = nullptr;
47 2x return *this;
48 }
49
50 void
51 1x file_stdio::
52 native_handle(std::FILE* f)
53 {
54 1x if(f_)
55 1x fclose(f_);
56 1x f_ = f;
57 1x }
58
59 void
60 4x file_stdio::
61 close(
62 system::error_code& ec)
63 {
64 4x if(f_)
65 {
66 4x int failed = fclose(f_);
67 4x f_ = nullptr;
68 4x if(failed)
69 {
70 ec.assign(errno,
71 system::generic_category());
72 return;
73 }
74 }
75 4x ec = {};
76 }
77
78 void
79 21x file_stdio::
80 open(char const* path, file_mode mode,
81 system::error_code& ec)
82 {
83 21x if(f_)
84 {
85 1x fclose(f_);
86 1x f_ = nullptr;
87 }
88 21x 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 21x switch(mode)
98 {
99 2x default:
100 case file_mode::read:
101 #ifdef _WIN32
102 s = L"rb";
103 #else
104 2x s = "rb";
105 #endif
106 2x break;
107
108 1x case file_mode::scan:
109 #ifdef _WIN32
110 s = L"rbS";
111 #else
112 1x s = "rb";
113 #endif
114 1x break;
115
116 10x case file_mode::write:
117 #ifdef _WIN32
118 s = L"wb+";
119 #else
120 10x s = "wb+";
121 #endif
122 10x break;
123
124 2x 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 2x s = "wbx";
150 #endif
151 2x break;
152 }
153
154 2x case file_mode::write_existing:
155 #ifdef _WIN32
156 s = L"rb+";
157 #else
158 2x s = "rb+";
159 #endif
160 2x break;
161
162 2x case file_mode::append:
163 #ifdef _WIN32
164 s = L"ab";
165 #else
166 2x s = "ab";
167 #endif
168 2x break;
169
170 2x 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 2x std::fopen(path, "rb+");
185 2x if(! f0)
186 {
187 1x ec.assign(errno,
188 system::generic_category());
189 1x return;
190 }
191 #endif
192 1x std::fclose(f0);
193 #ifdef _WIN32
194 s = L"ab";
195 #else
196 1x s = "ab";
197 #endif
198 1x 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 20x f_ = std::fopen(path, s);
214 20x if(! f_)
215 {
216 2x ec.assign(errno,
217 system::generic_category());
218 2x return;
219 }
220 #endif
221 }
222
223 std::uint64_t
224 2x file_stdio::
225 size(
226 system::error_code& ec) const
227 {
228 2x if(! f_)
229 {
230 1x ec = make_error_code(
231 system::errc::bad_file_descriptor);
232 1x return 0;
233 }
234 1x long pos = std::ftell(f_);
235 1x if(pos == -1L)
236 {
237 ec.assign(errno,
238 system::generic_category());
239 return 0;
240 }
241 1x int result = std::fseek(f_, 0, SEEK_END);
242 1x if(result != 0)
243 {
244 ec.assign(errno,
245 system::generic_category());
246 return 0;
247 }
248 1x long size = std::ftell(f_);
249 1x if(size == -1L)
250 {
251 ec.assign(errno,
252 system::generic_category());
253 std::fseek(f_, pos, SEEK_SET);
254 return 0;
255 }
256 1x result = std::fseek(f_, pos, SEEK_SET);
257 1x if(result != 0)
258 ec.assign(errno,
259 system::generic_category());
260 else
261 1x ec = {};
262 1x return size;
263 }
264
265 std::uint64_t
266 3x file_stdio::
267 pos(
268 system::error_code& ec) const
269 {
270 3x if(! f_)
271 {
272 1x ec = make_error_code(
273 system::errc::bad_file_descriptor);
274 1x return 0;
275 }
276 2x long pos = std::ftell(f_);
277 2x if(pos == -1L)
278 {
279 ec.assign(errno,
280 system::generic_category());
281 return 0;
282 }
283 2x ec = {};
284 2x return pos;
285 }
286
287 void
288 2x file_stdio::
289 seek(std::uint64_t offset,
290 system::error_code& ec)
291 {
292 2x if(! f_)
293 {
294 1x ec = make_error_code(
295 system::errc::bad_file_descriptor);
296 1x return;
297 }
298 1x 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 1x int result = std::fseek(f_,
305 static_cast<long>(offset), SEEK_SET);
306 1x if(result != 0)
307 ec.assign(errno,
308 system::generic_category());
309 else
310 1x ec = {};
311 }
312
313 std::size_t
314 3x file_stdio::
315 read(void* buffer, std::size_t n,
316 system::error_code& ec)
317 {
318 3x if(! f_)
319 {
320 1x ec = make_error_code(
321 system::errc::bad_file_descriptor);
322 1x return 0;
323 }
324 2x auto nread = std::fread(buffer, 1, n, f_);
325 2x if(std::ferror(f_))
326 {
327 ec.assign(errno,
328 system::generic_category());
329 return 0;
330 }
331 2x return nread;
332 }
333
334 std::size_t
335 5x file_stdio::
336 write(void const* buffer, std::size_t n,
337 system::error_code& ec)
338 {
339 5x if(! f_)
340 {
341 1x ec = make_error_code(
342 system::errc::bad_file_descriptor);
343 1x return 0;
344 }
345 4x auto nwritten = std::fwrite(buffer, 1, n, f_);
346 4x if(std::ferror(f_))
347 {
348 ec.assign(errno,
349 system::generic_category());
350 return 0;
351 }
352 4x return nwritten;
353 }
354
355 } // detail
356 } // http
357 } // boost
358