GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/file_posix.cpp
Date: 2024-05-23 18:56:45
Exec Total Coverage
Lines: 126 151 83.4%
Functions: 12 12 100.0%
Branches: 40 57 70.2%

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