GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/file_posix.ipp
Date: 2023-12-22 17:54:30
Exec Total Coverage
Lines: 125 150 83.3%
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 #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 51 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 51 int ev = 0;
64
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 33 times.
51 if(fd != -1)
65 {
66
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if(::close(fd) != 0)
67 ev = errno;
68 18 fd = -1;
69 }
70 51 return ev;
71 }
72
73 23 file_posix::
74 23 ~file_posix()
75 {
76 23 native_close(fd_);
77 23 }
78
79 1 file_posix::
80 file_posix(
81 1 file_posix&& other) noexcept
82 1 : fd_(boost::exchange(other.fd_, -1))
83 {
84 1 }
85
86 file_posix&
87 3 file_posix::
88 operator=(
89 file_posix&& other) noexcept
90 {
91
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(&other == this)
92 1 return *this;
93 2 native_close(fd_);
94 2 fd_ = other.fd_;
95 2 other.fd_ = -1;
96 2 return *this;
97 }
98
99 void
100 1 file_posix::
101 native_handle(native_handle_type fd)
102 {
103 1 native_close(fd_);
104 1 fd_ = fd;
105 1 }
106
107 void
108 4 file_posix::
109 close(
110 system::error_code& ec)
111 {
112 4 auto const ev = native_close(fd_);
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(ev)
114 ec.assign(ev,
115 system::system_category());
116 else
117 4 ec = {};
118 4 }
119
120 void
121 21 file_posix::
122 open(char const* path, file_mode mode, system::error_code& ec)
123 {
124 21 auto const ev = native_close(fd_);
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if(ev)
126 ec.assign(ev,
127 system::system_category());
128 else
129 21 ec = {};
130
131 21 int f = 0;
132 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
133 21 int advise = 0;
134 #endif
135
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)
136 {
137 2 default:
138 case file_mode::read:
139 2 f = O_RDONLY;
140 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
141 2 advise = POSIX_FADV_RANDOM;
142 #endif
143 2 break;
144 1 case file_mode::scan:
145 1 f = O_RDONLY;
146 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
147 1 advise = POSIX_FADV_SEQUENTIAL;
148 #endif
149 1 break;
150
151 10 case file_mode::write:
152 10 f = O_RDWR | O_CREAT | O_TRUNC;
153 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
154 10 advise = POSIX_FADV_RANDOM;
155 #endif
156 10 break;
157
158 2 case file_mode::write_new:
159 2 f = O_RDWR | O_CREAT | O_EXCL;
160 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
161 2 advise = POSIX_FADV_RANDOM;
162 #endif
163 2 break;
164
165 2 case file_mode::write_existing:
166 2 f = O_RDWR | O_EXCL;
167 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
168 2 advise = POSIX_FADV_RANDOM;
169 #endif
170 2 break;
171
172 2 case file_mode::append:
173 2 f = O_WRONLY | O_CREAT | O_APPEND;
174 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
175 2 advise = POSIX_FADV_SEQUENTIAL;
176 #endif
177 2 break;
178
179 2 case file_mode::append_existing:
180 2 f = O_WRONLY | O_APPEND;
181 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
182 2 advise = POSIX_FADV_SEQUENTIAL;
183 #endif
184 2 break;
185 }
186 for(;;)
187 {
188 21 fd_ = ::open(path, f, 0644);
189
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
21 if(fd_ != -1)
190 18 break;
191 3 auto const ev = errno;
192
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(ev != EINTR)
193 {
194 3 ec.assign(ev,
195 system::system_category());
196 3 return;
197 }
198 }
199 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
200
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 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 18 ec = {};
210 }
211
212 std::uint64_t
213 2 file_posix::
214 size(
215 system::error_code& ec) const
216 {
217
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if(fd_ == -1)
218 {
219 ec = make_error_code(
220 1 system::errc::bad_file_descriptor);
221 1 return 0;
222 }
223 struct stat st;
224
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(::fstat(fd_, &st) != 0)
225 {
226 ec.assign(errno,
227 system::system_category());
228 return 0;
229 }
230 1 ec = {};
231 1 return st.st_size;
232 }
233
234 std::uint64_t
235 3 file_posix::
236 pos(
237 system::error_code& ec) const
238 {
239
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(fd_ == -1)
240 {
241 ec = make_error_code(
242 1 system::errc::bad_file_descriptor);
243 1 return 0;
244 }
245 2 auto const result = ::lseek(fd_, 0, SEEK_CUR);
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(result == (off_t)-1)
247 {
248 ec.assign(errno,
249 system::system_category());
250 return 0;
251 }
252 2 ec = {};
253 2 return result;
254 }
255
256 void
257 2 file_posix::
258 seek(std::uint64_t offset,
259 system::error_code& ec)
260 {
261
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if(fd_ == -1)
262 {
263 ec = make_error_code(
264 1 system::errc::bad_file_descriptor);
265 1 return;
266 }
267 1 auto const result = ::lseek(fd_, offset, SEEK_SET);
268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(result == static_cast<off_t>(-1))
269 {
270 ec.assign(errno,
271 system::system_category());
272 return;
273 }
274 1 ec = {};
275 }
276
277 std::size_t
278 3 file_posix::
279 read(void* buffer, std::size_t n,
280 system::error_code& ec) const
281 {
282
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(fd_ == -1)
283 {
284 ec = make_error_code(
285 1 system::errc::bad_file_descriptor);
286 1 return 0;
287 }
288 2 std::size_t nread = 0;
289
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 while(n > 0)
290 {
291 // <limits> not required to define SSIZE_MAX so we avoid it
292 2 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 2 n, ssmax);
297
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto const result = ::read(fd_, buffer, amount);
298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(result == 0)
308 {
309 // short read
310 return nread;
311 }
312 2 n -= result;
313 2 nread += result;
314 2 buffer = static_cast<char*>(buffer) + result;
315 }
316 2 return nread;
317 }
318
319 std::size_t
320 5 file_posix::
321 write(void const* buffer, std::size_t n,
322 system::error_code& ec)
323 {
324
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if(fd_ == -1)
325 {
326 ec = make_error_code(
327 1 system::errc::bad_file_descriptor);
328 1 return 0;
329 }
330 4 std::size_t nwritten = 0;
331
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while(n > 0)
332 {
333 // <limits> not required to define SSIZE_MAX so we avoid it
334 4 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 4 n, ssmax);
339
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 auto const result = ::write(fd_, buffer, amount);
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 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 4 n -= result;
350 4 nwritten += result;
351 4 buffer = static_cast<char const*>(buffer) + result;
352 }
353 4 return nwritten;
354 }
355
356 } // http_proto
357 } // boost
358
359 #endif
360
361 #endif
362