LCOV - code coverage report
Current view: top level - http_proto/impl - file_posix.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 125 150 83.3 %
Date: 2023-12-22 17:54:30 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.15