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