LCOV - code coverage report
Current view: top level - src/detail - file_posix.cpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 83.4 % 151 126 25
Test Date: 2026-06-13 19:44:58 Functions: 100.0 % 12 12

           TLA  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
       8                 : //
       9                 : 
      10                 : #include <boost/http/detail/file_posix.hpp>
      11                 : 
      12                 : #if BOOST_HTTP_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_NO_POSIX_FADVISE)
      24                 : # if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
      25                 : #  define BOOST_HTTP_NO_POSIX_FADVISE
      26                 : # endif
      27                 : #endif
      28                 : 
      29                 : #if ! defined(BOOST_HTTP_USE_POSIX_FADVISE)
      30                 : # if ! defined(BOOST_HTTP_NO_POSIX_FADVISE)
      31                 : #  define BOOST_HTTP_USE_POSIX_FADVISE 1
      32                 : # else
      33                 : #  define BOOST_HTTP_USE_POSIX_FADVISE 0
      34                 : # endif
      35                 : #endif
      36                 : 
      37                 : namespace boost {
      38                 : namespace http {
      39                 : namespace detail {
      40                 : 
      41                 : int
      42 HIT         106 : 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             106 :     int ev = 0;
      62             106 :     if(fd != -1)
      63                 :     {
      64              36 :         if(::close(fd) != 0)
      65 MIS           0 :             ev = errno;
      66 HIT          36 :         fd = -1;
      67                 :     }
      68             106 :     return ev;
      69                 : }
      70                 : 
      71              48 : file_posix::
      72                 : ~file_posix()
      73                 : {
      74              48 :     native_close(fd_);
      75              48 : }
      76                 : 
      77               2 : file_posix::
      78                 : file_posix(
      79               2 :     file_posix&& other) noexcept
      80               2 :     : fd_(boost::exchange(other.fd_, -1))
      81                 : {
      82               2 : }
      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               8 : file_posix::
     107                 : close(
     108                 :     system::error_code& ec)
     109                 : {
     110               8 :     auto const ev = native_close(fd_);
     111               8 :     if(ev)
     112 MIS           0 :         ec.assign(ev,
     113                 :             system::system_category());
     114                 :     else
     115 HIT           8 :         ec = {};
     116               8 : }
     117                 : 
     118                 : void
     119              44 : file_posix::
     120                 : open(char const* path, file_mode mode, system::error_code& ec)
     121                 : {
     122              44 :     auto const ev = native_close(fd_);
     123              44 :     if(ev)
     124 MIS           0 :         ec.assign(ev,
     125                 :             system::system_category());
     126                 :     else
     127 HIT          44 :         ec = {};
     128                 : 
     129              44 :     int f = 0;
     130                 : #if BOOST_HTTP_USE_POSIX_FADVISE
     131              44 :     int advise = 0;
     132                 : #endif
     133              44 :     switch(mode)
     134                 :     {
     135               4 :     default:
     136                 :     case file_mode::read:
     137               4 :         f = O_RDONLY;
     138                 :     #if BOOST_HTTP_USE_POSIX_FADVISE
     139               4 :         advise = POSIX_FADV_RANDOM;
     140                 :     #endif
     141               4 :         break;
     142               4 :     case file_mode::scan:
     143               4 :         f = O_RDONLY;
     144                 :     #if BOOST_HTTP_USE_POSIX_FADVISE
     145               4 :         advise = POSIX_FADV_SEQUENTIAL;
     146                 :     #endif
     147               4 :         break;
     148                 : 
     149              20 :     case file_mode::write:
     150              20 :         f = O_RDWR | O_CREAT | O_TRUNC;
     151                 :     #if BOOST_HTTP_USE_POSIX_FADVISE
     152              20 :         advise = POSIX_FADV_RANDOM;
     153                 :     #endif
     154              20 :         break;
     155                 : 
     156               4 :     case file_mode::write_new:
     157               4 :         f = O_RDWR | O_CREAT | O_EXCL;
     158                 :     #if BOOST_HTTP_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_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_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_USE_POSIX_FADVISE
     180               4 :         advise = POSIX_FADV_SEQUENTIAL;
     181                 :     #endif
     182               4 :         break;
     183                 :     }
     184                 :     for(;;)
     185                 :     {
     186              44 :         fd_ = ::open(path, f, 0644);
     187              44 :         if(fd_ != -1)
     188              36 :             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 MIS           0 :     }
     197                 : #if BOOST_HTTP_USE_POSIX_FADVISE
     198 HIT          36 :     if(::posix_fadvise(fd_, 0, 0, advise))
     199                 :     {
     200 MIS           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 HIT          36 :     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 MIS           0 :         ec.assign(errno,
     225                 :             system::system_category());
     226               0 :         return 0;
     227                 :     }
     228 HIT           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 MIS           0 :         ec.assign(errno,
     247                 :             system::system_category());
     248               0 :         return 0;
     249                 :     }
     250 HIT           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 MIS           0 :         ec.assign(errno,
     269                 :             system::system_category());
     270               0 :         return;
     271                 :     }
     272 HIT           2 :     ec = {};
     273                 : }
     274                 : 
     275                 : std::size_t
     276               7 : file_posix::
     277                 : read(void* buffer, std::size_t n,
     278                 :     system::error_code& ec)
     279                 : {
     280               7 :     if(fd_ == -1)
     281                 :     {
     282               3 :         ec = make_error_code(
     283                 :             system::errc::bad_file_descriptor);
     284               3 :         return 0;
     285                 :     }
     286               4 :     std::size_t nread = 0;
     287               8 :     while(n > 0)
     288                 :     {
     289                 :         // <limits> not required to define SSIZE_MAX so we avoid it
     290               4 :         constexpr auto ssmax =
     291                 :             static_cast<std::size_t>((std::numeric_limits<
     292                 :                 decltype(::read(fd_, buffer, n))>::max)());
     293               4 :         auto const amount = (std::min)(
     294               4 :             n, ssmax);
     295               4 :         auto const result = ::read(fd_, buffer, amount);
     296               4 :         if(result == -1)
     297                 :         {
     298 MIS           0 :             auto const ev = errno;
     299               0 :             if(ev == EINTR)
     300               0 :                 continue;
     301               0 :             ec.assign(ev,
     302                 :                 system::system_category());
     303               0 :             return nread;
     304                 :         }
     305 HIT           4 :         if(result == 0)
     306                 :         {
     307                 :             // short read
     308 MIS           0 :             return nread;
     309                 :         }
     310 HIT           4 :         n -= result;
     311               4 :         nread += result;
     312               4 :         buffer = static_cast<char*>(buffer) + result;
     313                 :     }
     314               4 :     return nread;
     315                 : }
     316                 : 
     317                 : std::size_t
     318              11 : file_posix::
     319                 : write(void const* buffer, std::size_t n,
     320                 :     system::error_code& ec)
     321                 : {
     322              11 :     if(fd_ == -1)
     323                 :     {
     324               3 :         ec = make_error_code(
     325                 :             system::errc::bad_file_descriptor);
     326               3 :         return 0;
     327                 :     }
     328               8 :     std::size_t nwritten = 0;
     329              16 :     while(n > 0)
     330                 :     {
     331                 :         // <limits> not required to define SSIZE_MAX so we avoid it
     332               8 :         constexpr auto ssmax =
     333                 :             static_cast<std::size_t>((std::numeric_limits<
     334                 :                 decltype(::write(fd_, buffer, n))>::max)());
     335               8 :         auto const amount = (std::min)(
     336               8 :             n, ssmax);
     337               8 :         auto const result = ::write(fd_, buffer, amount);
     338               8 :         if(result == -1)
     339                 :         {
     340 MIS           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 HIT           8 :         n -= result;
     348               8 :         nwritten += result;
     349               8 :         buffer = static_cast<char const*>(buffer) + result;
     350                 :     }
     351               8 :     return nwritten;
     352                 : }
     353                 : 
     354                 : } // detail
     355                 : } // http
     356                 : } // boost
     357                 : 
     358                 : #endif
        

Generated by: LCOV version 2.3