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