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

Generated by: LCOV version 2.1