123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- //
- // Copyright (c) 2015-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #ifndef BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
- #define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
- #include <boost/beast/core/file_posix.hpp>
- #if BOOST_BEAST_USE_POSIX_FILE
- #include <boost/core/exchange.hpp>
- #include <limits>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/uio.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <limits.h>
- #if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
- # if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
- # define BOOST_BEAST_NO_POSIX_FADVISE
- # endif
- #endif
- #if ! defined(BOOST_BEAST_USE_POSIX_FADVISE)
- # if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
- # define BOOST_BEAST_USE_POSIX_FADVISE 1
- # else
- # define BOOST_BEAST_USE_POSIX_FADVISE 0
- # endif
- #endif
- namespace boost {
- namespace beast {
- int
- file_posix::
- native_close(native_handle_type& fd)
- {
- /* https://github.com/boostorg/beast/issues/1445
- This function is tuned for Linux / Mac OS:
-
- * only calls close() once
- * returns the error directly to the caller
- * does not loop on EINTR
- If this is incorrect for the platform, then the
- caller will need to implement their own type
- meeting the File requirements and use the correct
- behavior.
- See:
- http://man7.org/linux/man-pages/man2/close.2.html
- */
- int ev = 0;
- if(fd != -1)
- {
- if(::close(fd) != 0)
- ev = errno;
- fd = -1;
- }
- return ev;
- }
- file_posix::
- ~file_posix()
- {
- native_close(fd_);
- }
- file_posix::
- file_posix(file_posix&& other)
- : fd_(boost::exchange(other.fd_, -1))
- {
- }
- file_posix&
- file_posix::
- operator=(file_posix&& other)
- {
- if(&other == this)
- return *this;
- native_close(fd_);
- fd_ = other.fd_;
- other.fd_ = -1;
- return *this;
- }
- void
- file_posix::
- native_handle(native_handle_type fd)
- {
- native_close(fd_);
- fd_ = fd;
- }
- void
- file_posix::
- close(error_code& ec)
- {
- auto const ev = native_close(fd_);
- if(ev)
- ec.assign(ev, system_category());
- else
- ec = {};
- }
- void
- file_posix::
- open(char const* path, file_mode mode, error_code& ec)
- {
- auto const ev = native_close(fd_);
- if(ev)
- ec.assign(ev, system_category());
- else
- ec = {};
- int f = 0;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- int advise = 0;
- #endif
- switch(mode)
- {
- default:
- case file_mode::read:
- f = O_RDONLY;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_RANDOM;
- #endif
- break;
- case file_mode::scan:
- f = O_RDONLY;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_SEQUENTIAL;
- #endif
- break;
- case file_mode::write:
- f = O_RDWR | O_CREAT | O_TRUNC;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_RANDOM;
- #endif
- break;
- case file_mode::write_new:
- f = O_RDWR | O_CREAT | O_EXCL;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_RANDOM;
- #endif
- break;
- case file_mode::write_existing:
- f = O_RDWR | O_EXCL;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_RANDOM;
- #endif
- break;
- case file_mode::append:
- f = O_WRONLY | O_CREAT | O_APPEND;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_SEQUENTIAL;
- #endif
- break;
- case file_mode::append_existing:
- f = O_WRONLY | O_APPEND;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_SEQUENTIAL;
- #endif
- break;
- }
- for(;;)
- {
- fd_ = ::open(path, f, 0644);
- if(fd_ != -1)
- break;
- auto const ev = errno;
- if(ev != EINTR)
- {
- ec.assign(ev, system_category());
- return;
- }
- }
- #if BOOST_BEAST_USE_POSIX_FADVISE
- if(::posix_fadvise(fd_, 0, 0, advise))
- {
- auto const ev = errno;
- native_close(fd_);
- ec.assign(ev, system_category());
- return;
- }
- #endif
- ec = {};
- }
- std::uint64_t
- file_posix::
- size(error_code& ec) const
- {
- if(fd_ == -1)
- {
- ec = make_error_code(errc::bad_file_descriptor);
- return 0;
- }
- struct stat st;
- if(::fstat(fd_, &st) != 0)
- {
- ec.assign(errno, system_category());
- return 0;
- }
- ec = {};
- return st.st_size;
- }
- std::uint64_t
- file_posix::
- pos(error_code& ec) const
- {
- if(fd_ == -1)
- {
- ec = make_error_code(errc::bad_file_descriptor);
- return 0;
- }
- auto const result = ::lseek(fd_, 0, SEEK_CUR);
- if(result == (off_t)-1)
- {
- ec.assign(errno, system_category());
- return 0;
- }
- ec = {};
- return result;
- }
- void
- file_posix::
- seek(std::uint64_t offset, error_code& ec)
- {
- if(fd_ == -1)
- {
- ec = make_error_code(errc::bad_file_descriptor);
- return;
- }
- auto const result = ::lseek(fd_, offset, SEEK_SET);
- if(result == static_cast<off_t>(-1))
- {
- ec.assign(errno, system_category());
- return;
- }
- ec = {};
- }
- std::size_t
- file_posix::
- read(void* buffer, std::size_t n, error_code& ec) const
- {
- if(fd_ == -1)
- {
- ec = make_error_code(errc::bad_file_descriptor);
- return 0;
- }
- std::size_t nread = 0;
- while(n > 0)
- {
- // <limits> not required to define SSIZE_MAX so we avoid it
- constexpr auto ssmax =
- static_cast<std::size_t>((std::numeric_limits<
- decltype(::read(fd_, buffer, n))>::max)());
- auto const amount = (std::min)(
- n, ssmax);
- auto const result = ::read(fd_, buffer, amount);
- if(result == -1)
- {
- auto const ev = errno;
- if(ev == EINTR)
- continue;
- ec.assign(ev, system_category());
- return nread;
- }
- if(result == 0)
- {
- // short read
- return nread;
- }
- n -= result;
- nread += result;
- buffer = static_cast<char*>(buffer) + result;
- }
- return nread;
- }
- std::size_t
- file_posix::
- write(void const* buffer, std::size_t n, error_code& ec)
- {
- if(fd_ == -1)
- {
- ec = make_error_code(errc::bad_file_descriptor);
- return 0;
- }
- std::size_t nwritten = 0;
- while(n > 0)
- {
- // <limits> not required to define SSIZE_MAX so we avoid it
- constexpr auto ssmax =
- static_cast<std::size_t>((std::numeric_limits<
- decltype(::write(fd_, buffer, n))>::max)());
- auto const amount = (std::min)(
- n, ssmax);
- auto const result = ::write(fd_, buffer, amount);
- if(result == -1)
- {
- auto const ev = errno;
- if(ev == EINTR)
- continue;
- ec.assign(ev, system_category());
- return nwritten;
- }
- n -= result;
- nwritten += result;
- buffer = static_cast<char const*>(buffer) + result;
- }
- return nwritten;
- }
- } // beast
- } // boost
- #endif
- #endif
|