GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/file_posix.ipp
Date: 2023-12-11 14:11:20
Exec Total Coverage
Lines: 0 150 0.0%
Functions: 0 12 0.0%
Branches: 0 57 0.0%

Line Branch Exec Source
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_POSIX_IPP
11 #define BOOST_HTTP_PROTO_IMPL_FILE_POSIX_IPP
12
13 #include <boost/http_proto/file_posix.hpp>
14
15 #if BOOST_HTTP_PROTO_USE_POSIX_FILE
16
17 #include <boost/core/exchange.hpp>
18 #include <limits>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <sys/uio.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <limits.h>
25
26 #if ! defined(BOOST_HTTP_PROTO_NO_POSIX_FADVISE)
27 # if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
28 # define BOOST_HTTP_PROTO_NO_POSIX_FADVISE
29 # endif
30 #endif
31
32 #if ! defined(BOOST_HTTP_PROTO_USE_POSIX_FADVISE)
33 # if ! defined(BOOST_HTTP_PROTO_NO_POSIX_FADVISE)
34 # define BOOST_HTTP_PROTO_USE_POSIX_FADVISE 1
35 # else
36 # define BOOST_HTTP_PROTO_USE_POSIX_FADVISE 0
37 # endif
38 #endif
39
40 namespace boost {
41 namespace http_proto {
42
43 int
44 file_posix::
45 native_close(native_handle_type& fd)
46 {
47 /* https://github.com/boostorg/beast/issues/1445
48
49 This function is tuned for Linux / Mac OS:
50
51 * only calls close() once
52 * returns the error directly to the caller
53 * does not loop on EINTR
54
55 If this is incorrect for the platform, then the
56 caller will need to implement their own type
57 meeting the File requirements and use the correct
58 behavior.
59
60 See:
61 http://man7.org/linux/man-pages/man2/close.2.html
62 */
63 int ev = 0;
64 if(fd != -1)
65 {
66 if(::close(fd) != 0)
67 ev = errno;
68 fd = -1;
69 }
70 return ev;
71 }
72
73 file_posix::
74 ~file_posix()
75 {
76 native_close(fd_);
77 }
78
79 file_posix::
80 file_posix(
81 file_posix&& other) noexcept
82 : fd_(boost::exchange(other.fd_, -1))
83 {
84 }
85
86 file_posix&
87 file_posix::
88 operator=(
89 file_posix&& other) noexcept
90 {
91 if(&other == this)
92 return *this;
93 native_close(fd_);
94 fd_ = other.fd_;
95 other.fd_ = -1;
96 return *this;
97 }
98
99 void
100 file_posix::
101 native_handle(native_handle_type fd)
102 {
103 native_close(fd_);
104 fd_ = fd;
105 }
106
107 void
108 file_posix::
109 close(
110 system::error_code& ec)
111 {
112 auto const ev = native_close(fd_);
113 if(ev)
114 ec.assign(ev,
115 system::system_category());
116 else
117 ec = {};
118 }
119
120 void
121 file_posix::
122 open(char const* path, file_mode mode, system::error_code& ec)
123 {
124 auto const ev = native_close(fd_);
125 if(ev)
126 ec.assign(ev,
127 system::system_category());
128 else
129 ec = {};
130
131 int f = 0;
132 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
133 int advise = 0;
134 #endif
135 switch(mode)
136 {
137 default:
138 case file_mode::read:
139 f = O_RDONLY;
140 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
141 advise = POSIX_FADV_RANDOM;
142 #endif
143 break;
144 case file_mode::scan:
145 f = O_RDONLY;
146 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
147 advise = POSIX_FADV_SEQUENTIAL;
148 #endif
149 break;
150
151 case file_mode::write:
152 f = O_RDWR | O_CREAT | O_TRUNC;
153 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
154 advise = POSIX_FADV_RANDOM;
155 #endif
156 break;
157
158 case file_mode::write_new:
159 f = O_RDWR | O_CREAT | O_EXCL;
160 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
161 advise = POSIX_FADV_RANDOM;
162 #endif
163 break;
164
165 case file_mode::write_existing:
166 f = O_RDWR | O_EXCL;
167 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
168 advise = POSIX_FADV_RANDOM;
169 #endif
170 break;
171
172 case file_mode::append:
173 f = O_WRONLY | O_CREAT | O_APPEND;
174 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
175 advise = POSIX_FADV_SEQUENTIAL;
176 #endif
177 break;
178
179 case file_mode::append_existing:
180 f = O_WRONLY | O_APPEND;
181 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
182 advise = POSIX_FADV_SEQUENTIAL;
183 #endif
184 break;
185 }
186 for(;;)
187 {
188 fd_ = ::open(path, f, 0644);
189 if(fd_ != -1)
190 break;
191 auto const ev = errno;
192 if(ev != EINTR)
193 {
194 ec.assign(ev,
195 system::system_category());
196 return;
197 }
198 }
199 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
200 if(::posix_fadvise(fd_, 0, 0, advise))
201 {
202 auto const ev = errno;
203 native_close(fd_);
204 ec.assign(ev,
205 system::system_category());
206 return;
207 }
208 #endif
209 ec = {};
210 }
211
212 std::uint64_t
213 file_posix::
214 size(
215 system::error_code& ec) const
216 {
217 if(fd_ == -1)
218 {
219 ec = make_error_code(
220 system::errc::bad_file_descriptor);
221 return 0;
222 }
223 struct stat st;
224 if(::fstat(fd_, &st) != 0)
225 {
226 ec.assign(errno,
227 system::system_category());
228 return 0;
229 }
230 ec = {};
231 return st.st_size;
232 }
233
234 std::uint64_t
235 file_posix::
236 pos(
237 system::error_code& ec) const
238 {
239 if(fd_ == -1)
240 {
241 ec = make_error_code(
242 system::errc::bad_file_descriptor);
243 return 0;
244 }
245 auto const result = ::lseek(fd_, 0, SEEK_CUR);
246 if(result == (off_t)-1)
247 {
248 ec.assign(errno,
249 system::system_category());
250 return 0;
251 }
252 ec = {};
253 return result;
254 }
255
256 void
257 file_posix::
258 seek(std::uint64_t offset,
259 system::error_code& ec)
260 {
261 if(fd_ == -1)
262 {
263 ec = make_error_code(
264 system::errc::bad_file_descriptor);
265 return;
266 }
267 auto const result = ::lseek(fd_, offset, SEEK_SET);
268 if(result == static_cast<off_t>(-1))
269 {
270 ec.assign(errno,
271 system::system_category());
272 return;
273 }
274 ec = {};
275 }
276
277 std::size_t
278 file_posix::
279 read(void* buffer, std::size_t n,
280 system::error_code& ec) const
281 {
282 if(fd_ == -1)
283 {
284 ec = make_error_code(
285 system::errc::bad_file_descriptor);
286 return 0;
287 }
288 std::size_t nread = 0;
289 while(n > 0)
290 {
291 // <limits> not required to define SSIZE_MAX so we avoid it
292 constexpr auto ssmax =
293 static_cast<std::size_t>((std::numeric_limits<
294 decltype(::read(fd_, buffer, n))>::max)());
295 auto const amount = (std::min)(
296 n, ssmax);
297 auto const result = ::read(fd_, buffer, amount);
298 if(result == -1)
299 {
300 auto const ev = errno;
301 if(ev == EINTR)
302 continue;
303 ec.assign(ev,
304 system::system_category());
305 return nread;
306 }
307 if(result == 0)
308 {
309 // short read
310 return nread;
311 }
312 n -= result;
313 nread += result;
314 buffer = static_cast<char*>(buffer) + result;
315 }
316 return nread;
317 }
318
319 std::size_t
320 file_posix::
321 write(void const* buffer, std::size_t n,
322 system::error_code& ec)
323 {
324 if(fd_ == -1)
325 {
326 ec = make_error_code(
327 system::errc::bad_file_descriptor);
328 return 0;
329 }
330 std::size_t nwritten = 0;
331 while(n > 0)
332 {
333 // <limits> not required to define SSIZE_MAX so we avoid it
334 constexpr auto ssmax =
335 static_cast<std::size_t>((std::numeric_limits<
336 decltype(::write(fd_, buffer, n))>::max)());
337 auto const amount = (std::min)(
338 n, ssmax);
339 auto const result = ::write(fd_, buffer, amount);
340 if(result == -1)
341 {
342 auto const ev = errno;
343 if(ev == EINTR)
344 continue;
345 ec.assign(ev,
346 system::system_category());
347 return nwritten;
348 }
349 n -= result;
350 nwritten += result;
351 buffer = static_cast<char const*>(buffer) + result;
352 }
353 return nwritten;
354 }
355
356 } // http_proto
357 } // boost
358
359 #endif
360
361 #endif
362