LCOV - code coverage report
Current view: top level - http_proto/impl - file_posix.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 0 150 0.0 %
Date: 2023-01-15 07:18:31 Functions: 0 12 0.0 %

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2022 Vinnie Falco (vinnie dot falco at gmail dot 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           0 : 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           0 :     int ev = 0;
      64           0 :     if(fd != -1)
      65             :     {
      66           0 :         if(::close(fd) != 0)
      67           0 :             ev = errno;
      68           0 :         fd = -1;
      69             :     }
      70           0 :     return ev;
      71             : }
      72             : 
      73           0 : file_posix::
      74           0 : ~file_posix()
      75             : {
      76           0 :     native_close(fd_);
      77           0 : }
      78             : 
      79           0 : file_posix::
      80             : file_posix(
      81           0 :     file_posix&& other) noexcept
      82           0 :     : fd_(boost::exchange(other.fd_, -1))
      83             : {
      84           0 : }
      85             : 
      86             : file_posix&
      87           0 : file_posix::
      88             : operator=(
      89             :     file_posix&& other) noexcept
      90             : {
      91           0 :     if(&other == this)
      92           0 :         return *this;
      93           0 :     native_close(fd_);
      94           0 :     fd_ = other.fd_;
      95           0 :     other.fd_ = -1;
      96           0 :     return *this;
      97             : }
      98             : 
      99             : void
     100           0 : file_posix::
     101             : native_handle(native_handle_type fd)
     102             : {
     103           0 :     native_close(fd_);
     104           0 :     fd_ = fd;
     105           0 : }
     106             : 
     107             : void
     108           0 : file_posix::
     109             : close(error_code& ec)
     110             : {
     111           0 :     auto const ev = native_close(fd_);
     112           0 :     if(ev)
     113           0 :         ec.assign(ev, system_category());
     114             :     else
     115           0 :         ec = {};
     116           0 : }
     117             : 
     118             : void
     119           0 : file_posix::
     120             : open(char const* path, file_mode mode, error_code& ec)
     121             : {
     122           0 :     auto const ev = native_close(fd_);
     123           0 :     if(ev)
     124           0 :         ec.assign(ev, system_category());
     125             :     else
     126           0 :         ec = {};
     127             : 
     128           0 :     int f = 0;
     129             : #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     130           0 :     int advise = 0;
     131             : #endif
     132           0 :     switch(mode)
     133             :     {
     134           0 :     default:
     135             :     case file_mode::read:
     136           0 :         f = O_RDONLY;
     137             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     138           0 :         advise = POSIX_FADV_RANDOM;
     139             :     #endif
     140           0 :         break;
     141           0 :     case file_mode::scan:
     142           0 :         f = O_RDONLY;
     143             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     144           0 :         advise = POSIX_FADV_SEQUENTIAL;
     145             :     #endif
     146           0 :         break;
     147             : 
     148           0 :     case file_mode::write:
     149           0 :         f = O_RDWR | O_CREAT | O_TRUNC;
     150             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     151           0 :         advise = POSIX_FADV_RANDOM;
     152             :     #endif
     153           0 :         break;
     154             : 
     155           0 :     case file_mode::write_new:      
     156           0 :         f = O_RDWR | O_CREAT | O_EXCL;
     157             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     158           0 :         advise = POSIX_FADV_RANDOM;
     159             :     #endif
     160           0 :         break;
     161             : 
     162           0 :     case file_mode::write_existing: 
     163           0 :         f = O_RDWR | O_EXCL;
     164             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     165           0 :         advise = POSIX_FADV_RANDOM;
     166             :     #endif
     167           0 :         break;
     168             : 
     169           0 :     case file_mode::append:         
     170           0 :         f = O_WRONLY | O_CREAT | O_APPEND;
     171             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     172           0 :         advise = POSIX_FADV_SEQUENTIAL;
     173             :     #endif
     174           0 :         break;
     175             : 
     176           0 :     case file_mode::append_existing:
     177           0 :         f = O_WRONLY | O_APPEND;
     178             :     #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     179           0 :         advise = POSIX_FADV_SEQUENTIAL;
     180             :     #endif
     181           0 :         break;
     182             :     }
     183             :     for(;;)
     184             :     {
     185           0 :         fd_ = ::open(path, f, 0644);
     186           0 :         if(fd_ != -1)
     187           0 :             break;
     188           0 :         auto const ev = errno;
     189           0 :         if(ev != EINTR)
     190             :         {
     191           0 :             ec.assign(ev, system_category());
     192           0 :             return;
     193             :         }
     194           0 :     }
     195             : #if BOOST_HTTP_PROTO_USE_POSIX_FADVISE
     196           0 :     if(::posix_fadvise(fd_, 0, 0, advise))
     197             :     {
     198           0 :         auto const ev = errno;
     199           0 :         native_close(fd_);
     200           0 :         ec.assign(ev, system_category());
     201           0 :         return;
     202             :     }
     203             : #endif
     204           0 :     ec = {};
     205             : }
     206             : 
     207             : std::uint64_t
     208           0 : file_posix::
     209             : size(error_code& ec) const
     210             : {
     211           0 :     if(fd_ == -1)
     212             :     {
     213           0 :         ec = make_error_code(errc::bad_file_descriptor);
     214           0 :         return 0;
     215             :     }
     216             :     struct stat st;
     217           0 :     if(::fstat(fd_, &st) != 0)
     218             :     {
     219           0 :         ec.assign(errno, system_category());
     220           0 :         return 0;
     221             :     }
     222           0 :     ec = {};
     223           0 :     return st.st_size;
     224             : }
     225             : 
     226             : std::uint64_t
     227           0 : file_posix::
     228             : pos(error_code& ec) const
     229             : {
     230           0 :     if(fd_ == -1)
     231             :     {
     232           0 :         ec = make_error_code(errc::bad_file_descriptor);
     233           0 :         return 0;
     234             :     }
     235           0 :     auto const result = ::lseek(fd_, 0, SEEK_CUR);
     236           0 :     if(result == (off_t)-1)
     237             :     {
     238           0 :         ec.assign(errno, system_category());
     239           0 :         return 0;
     240             :     }
     241           0 :     ec = {};
     242           0 :     return result;
     243             : }
     244             : 
     245             : void
     246           0 : file_posix::
     247             : seek(std::uint64_t offset, error_code& ec)
     248             : {
     249           0 :     if(fd_ == -1)
     250             :     {
     251           0 :         ec = make_error_code(errc::bad_file_descriptor);
     252           0 :         return;
     253             :     }
     254           0 :     auto const result = ::lseek(fd_, offset, SEEK_SET);
     255           0 :     if(result == static_cast<off_t>(-1))
     256             :     {
     257           0 :         ec.assign(errno, system_category());
     258           0 :         return;
     259             :     }
     260           0 :     ec = {};
     261             : }
     262             : 
     263             : std::size_t
     264           0 : file_posix::
     265             : read(void* buffer, std::size_t n, error_code& ec) const
     266             : {
     267           0 :     if(fd_ == -1)
     268             :     {
     269           0 :         ec = make_error_code(errc::bad_file_descriptor);
     270           0 :         return 0;
     271             :     }
     272           0 :     std::size_t nread = 0;
     273           0 :     while(n > 0)
     274             :     {
     275             :         // <limits> not required to define SSIZE_MAX so we avoid it
     276           0 :         constexpr auto ssmax =
     277             :             static_cast<std::size_t>((std::numeric_limits<
     278             :                 decltype(::read(fd_, buffer, n))>::max)());
     279             :         auto const amount = (std::min)(
     280           0 :             n, ssmax);
     281           0 :         auto const result = ::read(fd_, buffer, amount);
     282           0 :         if(result == -1)
     283             :         {
     284           0 :             auto const ev = errno;
     285           0 :             if(ev == EINTR)
     286           0 :                 continue;
     287           0 :             ec.assign(ev, system_category());
     288           0 :             return nread;
     289             :         }
     290           0 :         if(result == 0)
     291             :         {
     292             :             // short read
     293           0 :             return nread;
     294             :         }
     295           0 :         n -= result;
     296           0 :         nread += result;
     297           0 :         buffer = static_cast<char*>(buffer) + result;
     298             :     }
     299           0 :     return nread;
     300             : }
     301             : 
     302             : std::size_t
     303           0 : file_posix::
     304             : write(void const* buffer, std::size_t n, error_code& ec)
     305             : {
     306           0 :     if(fd_ == -1)
     307             :     {
     308           0 :         ec = make_error_code(errc::bad_file_descriptor);
     309           0 :         return 0;
     310             :     }
     311           0 :     std::size_t nwritten = 0;
     312           0 :     while(n > 0)
     313             :     {
     314             :         // <limits> not required to define SSIZE_MAX so we avoid it
     315           0 :         constexpr auto ssmax =
     316             :             static_cast<std::size_t>((std::numeric_limits<
     317             :                 decltype(::write(fd_, buffer, n))>::max)());
     318             :         auto const amount = (std::min)(
     319           0 :             n, ssmax);
     320           0 :         auto const result = ::write(fd_, buffer, amount);
     321           0 :         if(result == -1)
     322             :         {
     323           0 :             auto const ev = errno;
     324           0 :             if(ev == EINTR)
     325           0 :                 continue;
     326           0 :             ec.assign(ev, system_category());
     327           0 :             return nwritten;
     328             :         }
     329           0 :         n -= result;
     330           0 :         nwritten += result;
     331           0 :         buffer = static_cast<char const*>(buffer) + result;
     332             :     }
     333           0 :     return nwritten;
     334             : }
     335             : 
     336             : } // http_proto
     337             : } // boost
     338             : 
     339             : #endif
     340             : 
     341             : #endif

Generated by: LCOV version 1.15