Add file_posix

This commit is contained in:
Vinnie Falco
2017-07-06 03:59:33 -07:00
parent e81026614a
commit eec5f1d8b6
9 changed files with 550 additions and 3 deletions

View File

@ -4,6 +4,7 @@ Version 74:
* Add file_win32
* Add file_body
* Remove common/file_body.hpp
* Add file_posix
--------------------------------------------------------------------------------

View File

@ -180,6 +180,7 @@
<entry valign="top">
<bridgehead renderas="sect3">&nbsp;</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>

View File

@ -285,6 +285,7 @@ INCLUDE_FILE_PATTERNS =
PREDEFINED = \
BEAST_DOXYGEN \
BEAST_USE_POSIX_FILE=1 \
BEAST_USE_WIN32_FILE=1
EXPAND_AS_DEFINED =

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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
View 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