GCC Code Coverage Report


Directory: libs/http_proto/
File: src/detail/file_posix.cpp
Date: 2025-09-21 18:08:15
Exec Total Coverage
Lines: 128 151 84.8%
Functions: 12 12 100.0%
Branches: 41 57 71.9%

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