Line data Source code
1 : //
2 : // Copyright (c) 2022 Vinnie Falco (vinnie dot falco at gmail dot 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(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, 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, error_code& ec)
80 : {
81 21 : if(f_)
82 : {
83 1 : fclose(f_);
84 1 : f_ = nullptr;
85 : }
86 21 : ec = {};
87 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
88 : boost::winapi::WCHAR_ const* s;
89 : detail::win32_unicode_path unicode_path(path, ec);
90 : if (ec)
91 : return;
92 : #else
93 : char const* s;
94 : #endif
95 21 : switch(mode)
96 : {
97 2 : default:
98 : case file_mode::read:
99 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
100 : s = L"rb";
101 : #else
102 2 : s = "rb";
103 : #endif
104 2 : break;
105 :
106 1 : case file_mode::scan:
107 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
108 : s = L"rbS";
109 : #else
110 1 : s = "rb";
111 : #endif
112 1 : break;
113 :
114 10 : case file_mode::write:
115 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
116 : s = L"wb+";
117 : #else
118 10 : s = "wb+";
119 : #endif
120 10 : break;
121 :
122 2 : case file_mode::write_new:
123 : {
124 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
125 : # if (defined(BOOST_MSVC) && BOOST_MSVC >= 1910) || (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION >= 141)
126 : s = L"wbx";
127 : # else
128 : std::FILE* f0;
129 : auto const ev = ::_wfopen_s(&f0, unicode_path.c_str(), L"rb");
130 : if(! ev)
131 : {
132 : std::fclose(f0);
133 : ec = make_error_code(errc::file_exists);
134 : return;
135 : }
136 : else if(ev !=
137 : errc::no_such_file_or_directory)
138 : {
139 : ec.assign(ev, generic_category());
140 : return;
141 : }
142 : s = L"wb";
143 : # endif
144 : #else
145 2 : s = "wbx";
146 : #endif
147 2 : break;
148 : }
149 :
150 2 : case file_mode::write_existing:
151 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
152 : s = L"rb+";
153 : #else
154 2 : s = "rb+";
155 : #endif
156 2 : break;
157 :
158 2 : case file_mode::append:
159 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
160 : s = L"ab";
161 : #else
162 2 : s = "ab";
163 : #endif
164 2 : break;
165 :
166 2 : case file_mode::append_existing:
167 : {
168 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
169 : std::FILE* f0;
170 : auto const ev =
171 : ::_wfopen_s(&f0, unicode_path.c_str(), L"rb+");
172 : if(ev)
173 : {
174 : ec.assign(ev, generic_category());
175 : return;
176 : }
177 : #else
178 : auto const f0 =
179 2 : std::fopen(path, "rb+");
180 2 : if(! f0)
181 : {
182 1 : ec.assign(errno, generic_category());
183 1 : return;
184 : }
185 : #endif
186 1 : std::fclose(f0);
187 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
188 : s = L"ab";
189 : #else
190 1 : s = "ab";
191 : #endif
192 1 : break;
193 : }
194 : }
195 :
196 : #if defined(BOOST_MSVC) || defined(_MSVC_STL_VERSION)
197 : auto const ev = ::_wfopen_s(&f_, unicode_path.c_str(), s);
198 : if(ev)
199 : {
200 : f_ = nullptr;
201 : ec.assign(ev, generic_category());
202 : return;
203 : }
204 : #else
205 20 : f_ = std::fopen(path, s);
206 20 : if(! f_)
207 : {
208 2 : ec.assign(errno, generic_category());
209 2 : return;
210 : }
211 : #endif
212 : }
213 :
214 : std::uint64_t
215 2 : file_stdio::
216 : size(error_code& ec) const
217 : {
218 2 : if(! f_)
219 : {
220 1 : ec = make_error_code(errc::bad_file_descriptor);
221 1 : return 0;
222 : }
223 1 : long pos = std::ftell(f_);
224 1 : if(pos == -1L)
225 : {
226 0 : ec.assign(errno, generic_category());
227 0 : return 0;
228 : }
229 1 : int result = std::fseek(f_, 0, SEEK_END);
230 1 : if(result != 0)
231 : {
232 0 : ec.assign(errno, generic_category());
233 0 : return 0;
234 : }
235 1 : long size = std::ftell(f_);
236 1 : if(size == -1L)
237 : {
238 0 : ec.assign(errno, generic_category());
239 0 : std::fseek(f_, pos, SEEK_SET);
240 0 : return 0;
241 : }
242 1 : result = std::fseek(f_, pos, SEEK_SET);
243 1 : if(result != 0)
244 0 : ec.assign(errno, generic_category());
245 : else
246 1 : ec = {};
247 1 : return size;
248 : }
249 :
250 : std::uint64_t
251 3 : file_stdio::
252 : pos(error_code& ec) const
253 : {
254 3 : if(! f_)
255 : {
256 1 : ec = make_error_code(errc::bad_file_descriptor);
257 1 : return 0;
258 : }
259 2 : long pos = std::ftell(f_);
260 2 : if(pos == -1L)
261 : {
262 0 : ec.assign(errno, generic_category());
263 0 : return 0;
264 : }
265 2 : ec = {};
266 2 : return pos;
267 : }
268 :
269 : void
270 2 : file_stdio::
271 : seek(std::uint64_t offset, error_code& ec)
272 : {
273 2 : if(! f_)
274 : {
275 1 : ec = make_error_code(errc::bad_file_descriptor);
276 1 : return;
277 : }
278 1 : if(offset > static_cast<std::uint64_t>((std::numeric_limits<long>::max)()))
279 : {
280 0 : ec = make_error_code(errc::invalid_seek);
281 0 : return;
282 : }
283 1 : int result = std::fseek(f_,
284 : static_cast<long>(offset), SEEK_SET);
285 1 : if(result != 0)
286 0 : ec.assign(errno, generic_category());
287 : else
288 1 : ec = {};
289 : }
290 :
291 : std::size_t
292 3 : file_stdio::
293 : read(void* buffer, std::size_t n, error_code& ec) const
294 : {
295 3 : if(! f_)
296 : {
297 1 : ec = make_error_code(errc::bad_file_descriptor);
298 1 : return 0;
299 : }
300 2 : auto nread = std::fread(buffer, 1, n, f_);
301 2 : if(std::ferror(f_))
302 : {
303 0 : ec.assign(errno, generic_category());
304 0 : return 0;
305 : }
306 2 : return nread;
307 : }
308 :
309 : std::size_t
310 5 : file_stdio::
311 : write(void const* buffer, std::size_t n, error_code& ec)
312 : {
313 5 : if(! f_)
314 : {
315 1 : ec = make_error_code(errc::bad_file_descriptor);
316 1 : return 0;
317 : }
318 4 : auto nwritten = std::fwrite(buffer, 1, n, f_);
319 4 : if(std::ferror(f_))
320 : {
321 0 : ec.assign(errno, generic_category());
322 0 : return 0;
323 : }
324 4 : return nwritten;
325 : }
326 :
327 : } // http_proto
328 : } // boost
329 :
330 : #endif
|