LCOV - code coverage report
Current view: top level - libs/http_proto/src/detail/file_posix.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 84.8 % 151 128
Test Date: 2025-09-21 18:08:14 Functions: 100.0 % 12 12

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

Generated by: LCOV version 2.1