mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 04:47:29 +02:00
Add file_posix
This commit is contained in:
@ -4,6 +4,7 @@ Version 74:
|
||||
* Add file_win32
|
||||
* Add file_body
|
||||
* Remove common/file_body.hpp
|
||||
* Add file_posix
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -180,6 +180,7 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3"> </bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.beast__file_posix">file_posix</link></member>
|
||||
<member><link linkend="beast.ref.beast__file_stdio">file_stdio</link></member>
|
||||
<member><link linkend="beast.ref.beast__file_win32">file_win32</link></member>
|
||||
<member><link linkend="beast.ref.beast__flat_buffer">flat_buffer</link></member>
|
||||
|
@ -285,6 +285,7 @@ INCLUDE_FILE_PATTERNS =
|
||||
|
||||
PREDEFINED = \
|
||||
BEAST_DOXYGEN \
|
||||
BEAST_USE_POSIX_FILE=1 \
|
||||
BEAST_USE_WIN32_FILE=1
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define BEAST_CORE_FILE_HPP
|
||||
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <beast/core/file_posix.hpp>
|
||||
#include <beast/core/file_stdio.hpp>
|
||||
#include <beast/core/file_win32.hpp>
|
||||
#include <boost/config.hpp>
|
||||
@ -20,12 +21,16 @@ namespace beast {
|
||||
This alias is set to the best available implementation
|
||||
of @b File given the platform and build settings.
|
||||
*/
|
||||
#if defined(BOOST_MSVC) && BEAST_USE_WIN32_FILE
|
||||
#if BEAST_DOXYGEN
|
||||
using file = implementation_defined;
|
||||
#else
|
||||
#if BEAST_USE_WIN32_FILE
|
||||
using file = file_win32;
|
||||
|
||||
#elif BEAST_USE_POSIX_FILE
|
||||
using file = file_posix;
|
||||
#else
|
||||
using file = file_stdio;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
171
include/beast/core/file_posix.hpp
Normal file
171
include/beast/core/file_posix.hpp
Normal file
@ -0,0 +1,171 @@
|
||||
//
|
||||
// Copyright (c) 2015-2016 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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CORE_FILE_POSIX_HPP
|
||||
#define BEAST_CORE_FILE_POSIX_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if ! defined(BEAST_NO_POSIX_FILE)
|
||||
# if ! defined(__APPLE__) && ! defined(__linux__)
|
||||
# define BEAST_NO_POSIX_FILE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ! defined(BEAST_USE_POSIX_FILE)
|
||||
# if ! defined(BEAST_NO_POSIX_FILE)
|
||||
# define BEAST_USE_POSIX_FILE 1
|
||||
# else
|
||||
# define BEAST_USE_POSIX_FILE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if BEAST_USE_POSIX_FILE
|
||||
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** An implementation of File for Win32.
|
||||
|
||||
This class implements a @b File using Win32 native interfaces.
|
||||
*/
|
||||
class file_posix
|
||||
{
|
||||
int fd_ = -1;
|
||||
|
||||
public:
|
||||
/** The type of the underlying file handle.
|
||||
|
||||
This is platform-specific.
|
||||
*/
|
||||
using native_handle_type = int;
|
||||
|
||||
/** Destructor
|
||||
|
||||
If the file is open it is first closed.
|
||||
*/
|
||||
~file_posix();
|
||||
|
||||
/** Constructor
|
||||
|
||||
There is no open file initially.
|
||||
*/
|
||||
file_posix() = default;
|
||||
|
||||
/** Constructor
|
||||
|
||||
The moved-from object behaves as if default constructed.
|
||||
*/
|
||||
file_posix(file_posix&& other);
|
||||
|
||||
/** Assignment
|
||||
|
||||
The moved-from object behaves as if default constructed.
|
||||
*/
|
||||
file_posix& operator=(file_posix&& other);
|
||||
|
||||
/// Returns the native handle associated with the file.
|
||||
native_handle_type
|
||||
native_handle() const
|
||||
{
|
||||
return fd_;
|
||||
}
|
||||
|
||||
/** Set the native handle associated with the file.
|
||||
|
||||
If the file is open it is first closed.
|
||||
|
||||
@param fd The native file handle to assign.
|
||||
*/
|
||||
void
|
||||
native_handle(native_handle_type fd);
|
||||
|
||||
/// Returns `true` if the file is open
|
||||
bool
|
||||
is_open() const
|
||||
{
|
||||
return fd_ != -1;
|
||||
}
|
||||
|
||||
/** Close the file if open
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
void
|
||||
close(error_code& ec);
|
||||
|
||||
/** Open a file at the given path with the specified mode
|
||||
|
||||
@param path The utf-8 encoded path to the file
|
||||
|
||||
@param mode The file mode to use
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
void
|
||||
open(char const* path, file_mode mode, error_code& ec);
|
||||
|
||||
/** Return the size of the open file
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
|
||||
@return The size in bytes
|
||||
*/
|
||||
std::uint64_t
|
||||
size(error_code& ec) const;
|
||||
|
||||
/** Return the current position in the open file
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
|
||||
@return The offset in bytes from the beginning of the file
|
||||
*/
|
||||
std::uint64_t
|
||||
pos(error_code& ec) const;
|
||||
|
||||
/** Adjust the current position in the open file
|
||||
|
||||
@param offset The offset in bytes from the beginning of the file
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
void
|
||||
seek(std::uint64_t offset, error_code& ec);
|
||||
|
||||
/** Read from the open file
|
||||
|
||||
@param buffer The buffer for storing the result of the read
|
||||
|
||||
@param n The number of bytes to read
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
std::size_t
|
||||
read(void* buffer, std::size_t n, error_code& ec) const;
|
||||
|
||||
/** Write to the open file
|
||||
|
||||
@param buffer The buffer holding the data to write
|
||||
|
||||
@param n The number of bytes to write
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
std::size_t
|
||||
write(void const* buffer, std::size_t n, error_code& ec);
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/file_posix.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
331
include/beast/core/impl/file_posix.ipp
Normal file
331
include/beast/core/impl/file_posix.ipp
Normal file
@ -0,0 +1,331 @@
|
||||
//
|
||||
// Copyright (c) 2015-2016 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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CORE_IMPL_FILE_POSIX_IPP
|
||||
#define BEAST_CORE_IMPL_FILE_POSIX_IPP
|
||||
|
||||
#include <limits>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline
|
||||
int
|
||||
file_posix_close(int fd)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(! ::close(fd))
|
||||
break;
|
||||
int const ev = errno;
|
||||
if(errno != EINTR)
|
||||
return ev;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
inline
|
||||
file_posix::
|
||||
~file_posix()
|
||||
{
|
||||
if(fd_ != -1)
|
||||
detail::file_posix_close(fd_);
|
||||
}
|
||||
|
||||
inline
|
||||
file_posix::
|
||||
file_posix(file_posix&& other)
|
||||
: fd_(other.fd_)
|
||||
{
|
||||
other.fd_ = -1;
|
||||
}
|
||||
|
||||
inline
|
||||
file_posix&
|
||||
file_posix::
|
||||
operator=(file_posix&& other)
|
||||
{
|
||||
if(&other == this)
|
||||
return *this;
|
||||
if(fd_ != -1)
|
||||
detail::file_posix_close(fd_);
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_posix::
|
||||
native_handle(native_handle_type fd)
|
||||
{
|
||||
if(fd_ != -1)
|
||||
detail::file_posix_close(fd_);
|
||||
fd_ = fd;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_posix::
|
||||
close(error_code& ec)
|
||||
{
|
||||
if(fd_ != -1)
|
||||
{
|
||||
auto const ev =
|
||||
detail::file_posix_close(fd_);
|
||||
if(ev)
|
||||
ec.assign(ev, generic_category());
|
||||
else
|
||||
ec.assign(0, ec.category());
|
||||
fd_ = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_posix::
|
||||
open(char const* path, file_mode mode, error_code& ec)
|
||||
{
|
||||
if(fd_ != -1)
|
||||
{
|
||||
auto const ev =
|
||||
detail::file_posix_close(fd_);
|
||||
if(ev)
|
||||
ec.assign(ev, generic_category());
|
||||
else
|
||||
ec.assign(0, ec.category());
|
||||
fd_ = -1;
|
||||
}
|
||||
int f = 0;
|
||||
int advise = 0;
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
case file_mode::read:
|
||||
f = O_RDONLY;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_RANDOM;
|
||||
#endif
|
||||
break;
|
||||
case file_mode::scan:
|
||||
f = O_RDONLY;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_SEQUENTIAL;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case file_mode::write:
|
||||
f = O_RDWR | O_CREAT | O_TRUNC;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_RANDOM;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case file_mode::write_new:
|
||||
f = O_RDWR | O_CREAT | O_EXCL;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_RANDOM;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case file_mode::write_existing:
|
||||
f = O_RDWR | O_EXCL;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_RANDOM;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case file_mode::append:
|
||||
f = O_RDWR | O_CREAT | O_TRUNC;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_SEQUENTIAL;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case file_mode::append_new:
|
||||
f = O_RDWR | O_CREAT | O_EXCL;
|
||||
#ifndef __APPLE__
|
||||
advise = POSIX_FADV_SEQUENTIAL;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case file_mode::append_existing:
|
||||
f = O_RDWR | O_EXCL;
|
||||
#ifndef __APPLE__
|
||||
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, generic_category());
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifndef __APPLE__
|
||||
if(::posix_fadvise(fd_, 0, 0, advise))
|
||||
{
|
||||
auto const ev = errno;
|
||||
detail::file_posix_close(fd_);
|
||||
fd_ = -1;
|
||||
ec.assign(ev, generic_category());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
file_posix::
|
||||
size(error_code& ec) const
|
||||
{
|
||||
if(fd_ == -1)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
BOOST_STATIC_ASSERT(
|
||||
sizeof(stat::st_size) == sizeof(std::uint64_t));
|
||||
struct stat st;
|
||||
if(::fstat(fd_, &st) != 0)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
file_posix::
|
||||
pos(error_code& ec) const
|
||||
{
|
||||
if(fd_ == -1)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
auto const result = ::lseek(fd_, 0, SEEK_CUR);
|
||||
if(result == (off_t)-1)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_posix::
|
||||
seek(std::uint64_t offset, error_code& ec)
|
||||
{
|
||||
if(fd_ == -1)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return;
|
||||
}
|
||||
auto const result = ::lseek(fd_, offset, SEEK_SET);
|
||||
if(result == static_cast<off_t>(-1))
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
file_posix::
|
||||
read(void* buffer, std::size_t n, error_code& ec) const
|
||||
{
|
||||
if(fd_ == -1)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
std::size_t nread = 0;
|
||||
while(n > 0)
|
||||
{
|
||||
auto const amount = static_cast<ssize_t>((std::min)(
|
||||
n, static_cast<std::size_t>(SSIZE_MAX)));
|
||||
auto const result = ::read(fd_, buffer, amount);
|
||||
if(result == -1)
|
||||
{
|
||||
auto const ev = errno;
|
||||
if(ev == EINTR)
|
||||
continue;
|
||||
ec.assign(ev, generic_category());
|
||||
return nread;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
// short read
|
||||
return nread;
|
||||
}
|
||||
n -= result;
|
||||
nread += result;
|
||||
buffer = reinterpret_cast<char*>(buffer) + result;
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
file_posix::
|
||||
write(void const* buffer, std::size_t n, error_code& ec)
|
||||
{
|
||||
if(fd_ == -1)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
std::size_t nwritten = 0;
|
||||
while(n > 0)
|
||||
{
|
||||
auto const amount = static_cast<ssize_t>((std::min)(
|
||||
n, static_cast<std::size_t>(SSIZE_MAX)));
|
||||
auto const result = ::write(fd_, buffer, amount);
|
||||
if(result == -1)
|
||||
{
|
||||
auto const ev = errno;
|
||||
if(ev == EINTR)
|
||||
continue;
|
||||
ec.assign(ev, generic_category());
|
||||
return nwritten;
|
||||
}
|
||||
n -= result;
|
||||
nwritten += result;
|
||||
buffer = reinterpret_cast<char const*>(buffer) + result;
|
||||
}
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -26,6 +26,7 @@ add_executable (core-tests
|
||||
drain_buffer.cpp
|
||||
error.cpp
|
||||
file.cpp
|
||||
file_posix.cpp
|
||||
file_stdio.cpp
|
||||
file_win32.cpp
|
||||
flat_buffer.cpp
|
||||
|
@ -20,6 +20,7 @@ unit-test core-tests :
|
||||
drain_buffer.cpp
|
||||
error.cpp
|
||||
file.cpp
|
||||
file_posix.cpp
|
||||
file_stdio.cpp
|
||||
file_win32.cpp
|
||||
flat_buffer.cpp
|
||||
|
35
test/core/file_posix.cpp
Normal file
35
test/core/file_posix.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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)
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/core/file_posix.hpp>
|
||||
|
||||
#if BEAST_USE_POSIX_FILE
|
||||
|
||||
#include "file_test.hpp"
|
||||
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class file_posix_test
|
||||
: public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
run()
|
||||
{
|
||||
doTestFile<file_posix>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(file_posix,core,beast);
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user