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