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

source code of boost/libs/beast/include/boost/beast/core/impl/file_stdio.ipp