GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/file_posix.ipp
Date: 2023-02-02 18:17:22
Exec Total Coverage
Lines: 0 145 0.0%
Functions: 0 12 0.0%
Branches: 0 57 0.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2022 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/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(error_code& ec)
110 {
111 ✗ auto const ev = native_close(fd_);
112 ✗ if(ev)
113 ✗ ec.assign(ev, system_category());
114 else
115 ✗ ec = {};
116 }
117
118 void
119 ✗ file_posix::
120 open(char const* path, file_mode mode, error_code& ec)
121 {
122 ✗ auto const ev = native_close(fd_);
123 ✗ if(ev)
124 ✗ ec.assign(ev, system_category());
125 else
126 ✗ ec = {};
127
128 ✗ int f = 0;
129 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
130 ✗ int advise = 0;
131 #endif
132 ✗ switch(mode)
133 {
134 ✗ default:
135 case file_mode::read:
136 ✗ f = O_RDONLY;
137 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
138 ✗ advise = POSIX_FADV_RANDOM;
139 #endif
140 ✗ break;
141 ✗ case file_mode::scan:
142 ✗ f = O_RDONLY;
143 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
144 ✗ advise = POSIX_FADV_SEQUENTIAL;
145 #endif
146 ✗ break;
147
148 ✗ case file_mode::write:
149 ✗ f = O_RDWR | O_CREAT | O_TRUNC;
150 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
151 ✗ advise = POSIX_FADV_RANDOM;
152 #endif
153 ✗ break;
154
155 ✗ case file_mode::write_new:
156 ✗ f = O_RDWR | O_CREAT | O_EXCL;
157 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
158 ✗ advise = POSIX_FADV_RANDOM;
159 #endif
160 ✗ break;
161
162 ✗ case file_mode::write_existing:
163 ✗ f = O_RDWR | O_EXCL;
164 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
165 ✗ advise = POSIX_FADV_RANDOM;
166 #endif
167 ✗ break;
168
169 ✗ case file_mode::append:
170 ✗ f = O_WRONLY | O_CREAT | O_APPEND;
171 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
172 ✗ advise = POSIX_FADV_SEQUENTIAL;
173 #endif
174 ✗ break;
175
176 ✗ case file_mode::append_existing:
177 ✗ f = O_WRONLY | O_APPEND;
178 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
179 ✗ advise = POSIX_FADV_SEQUENTIAL;
180 #endif
181 ✗ break;
182 }
183 for(;;)
184 {
185 ✗ fd_ = ::open(path, f, 0644);
186 ✗ if(fd_ != -1)
187 ✗ break;
188 ✗ auto const ev = errno;
189 ✗ if(ev != EINTR)
190 {
191 ✗ ec.assign(ev, system_category());
192 ✗ return;
193 }
194 }
195 #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
196 ✗ if(::posix_fadvise(fd_, 0, 0, advise))
197 {
198 ✗ auto const ev = errno;
199 ✗ native_close(fd_);
200 ✗ ec.assign(ev, system_category());
201 ✗ return;
202 }
203 #endif
204 ✗ ec = {};
205 }
206
207 std::uint64_t
208 ✗ file_posix::
209 size(error_code& ec) const
210 {
211 ✗ if(fd_ == -1)
212 {
213 ✗ ec = make_error_code(errc::bad_file_descriptor);
214 ✗ return 0;
215 }
216 struct stat st;
217 ✗ if(::fstat(fd_, &st) != 0)
218 {
219 ✗ ec.assign(errno, system_category());
220 ✗ return 0;
221 }
222 ✗ ec = {};
223 ✗ return st.st_size;
224 }
225
226 std::uint64_t
227 ✗ file_posix::
228 pos(error_code& ec) const
229 {
230 ✗ if(fd_ == -1)
231 {
232 ✗ ec = make_error_code(errc::bad_file_descriptor);
233 ✗ return 0;
234 }
235 ✗ auto const result = ::lseek(fd_, 0, SEEK_CUR);
236 ✗ if(result == (off_t)-1)
237 {
238 ✗ ec.assign(errno, system_category());
239 ✗ return 0;
240 }
241 ✗ ec = {};
242 ✗ return result;
243 }
244
245 void
246 ✗ file_posix::
247 seek(std::uint64_t offset, error_code& ec)
248 {
249 ✗ if(fd_ == -1)
250 {
251 ✗ ec = make_error_code(errc::bad_file_descriptor);
252 ✗ return;
253 }
254 ✗ auto const result = ::lseek(fd_, offset, SEEK_SET);
255 ✗ if(result == static_cast<off_t>(-1))
256 {
257 ✗ ec.assign(errno, system_category());
258 ✗ return;
259 }
260 ✗ ec = {};
261 }
262
263 std::size_t
264 ✗ file_posix::
265 read(void* buffer, std::size_t n, error_code& ec) const
266 {
267 ✗ if(fd_ == -1)
268 {
269 ✗ ec = make_error_code(errc::bad_file_descriptor);
270 ✗ return 0;
271 }
272 ✗ std::size_t nread = 0;
273 ✗ while(n > 0)
274 {
275 // <limits> not required to define SSIZE_MAX so we avoid it
276 ✗ constexpr auto ssmax =
277 static_cast<std::size_t>((std::numeric_limits<
278 decltype(::read(fd_, buffer, n))>::max)());
279 auto const amount = (std::min)(
280 ✗ n, ssmax);
281 ✗ auto const result = ::read(fd_, buffer, amount);
282 ✗ if(result == -1)
283 {
284 ✗ auto const ev = errno;
285 ✗ if(ev == EINTR)
286 ✗ continue;
287 ✗ ec.assign(ev, system_category());
288 ✗ return nread;
289 }
290 ✗ if(result == 0)
291 {
292 // short read
293 ✗ return nread;
294 }
295 ✗ n -= result;
296 ✗ nread += result;
297 ✗ buffer = static_cast<char*>(buffer) + result;
298 }
299 ✗ return nread;
300 }
301
302 std::size_t
303 ✗ file_posix::
304 write(void const* buffer, std::size_t n, error_code& ec)
305 {
306 ✗ if(fd_ == -1)
307 {
308 ✗ ec = make_error_code(errc::bad_file_descriptor);
309 ✗ return 0;
310 }
311 ✗ std::size_t nwritten = 0;
312 ✗ while(n > 0)
313 {
314 // <limits> not required to define SSIZE_MAX so we avoid it
315 ✗ constexpr auto ssmax =
316 static_cast<std::size_t>((std::numeric_limits<
317 decltype(::write(fd_, buffer, n))>::max)());
318 auto const amount = (std::min)(
319 ✗ n, ssmax);
320 ✗ auto const result = ::write(fd_, buffer, amount);
321 ✗ if(result == -1)
322 {
323 ✗ auto const ev = errno;
324 ✗ if(ev == EINTR)
325 ✗ continue;
326 ✗ ec.assign(ev, system_category());
327 ✗ return nwritten;
328 }
329 ✗ n -= result;
330 ✗ nwritten += result;
331 ✗ buffer = static_cast<char const*>(buffer) + result;
332 }
333 ✗ return nwritten;
334 }
335
336 } // http_proto
337 } // boost
338
339 #endif
340
341 #endif
342