boost/beast/core/impl/file_stdio.ipp
//
// 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_STDIO_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#include <boost/beast/core/file_stdio.hpp>
#include <boost/beast/core/detail/win32_unicode_path.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <limits>
namespace boost {
namespace beast {
file_stdio::
~file_stdio()
{
if(f_)
fclose(f_);
}
file_stdio::
file_stdio(file_stdio&& other)
: f_(boost::exchange(other.f_, nullptr))
{
}
file_stdio&
file_stdio::
operator=(file_stdio&& other)
{
if(&other == this)
return *this;
if(f_)
fclose(f_);
f_ = other.f_;
other.f_ = nullptr;
return *this;
}
void
file_stdio::
native_handle(std::FILE* f)
{
if(f_)
fclose(f_);
f_ = f;
}
void
file_stdio::
close(error_code& ec)
{
if(f_)
{
int failed = fclose(f_);
f_ = nullptr;
if(failed)
{
ec.assign(errno, generic_category());
return;
}
}
ec = {};
}
void
file_stdio::
open(char const* path, file_mode mode, error_code& ec)
{
if(f_)
{
fclose(f_);
f_ = nullptr;
}
ec = {};
#ifdef BOOST_MSVC
boost::winapi::WCHAR_ const* s;
detail::win32_unicode_path unicode_path(path, ec);
if (ec)
return;
#else
char const* s;
#endif
switch(mode)
{
default:
case file_mode::read:
#ifdef BOOST_MSVC
s = L"rb";
#else
s = "rb";
#endif
break;
case file_mode::scan:
#ifdef BOOST_MSVC
s = L"rbS";
#else
s = "rb";
#endif
break;
case file_mode::write:
#ifdef BOOST_MSVC
s = L"wb+";
#else
s = "wb+";
#endif
break;
case file_mode::write_new:
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
std::FILE* f0;
auto const ev = ::_wfopen_s(&f0, unicode_path.c_str(), L"rb");
if(! ev)
{
std::fclose(f0);
ec = make_error_code(errc::file_exists);
return;
}
else if(ev !=
errc::no_such_file_or_directory)
{
ec.assign(ev, generic_category());
return;
}
s = L"wb";
#elif defined(BOOST_MSVC)
s = L"wbx";
#else
s = "wbx";
#endif
break;
}
case file_mode::write_existing:
#ifdef BOOST_MSVC
s = L"rb+";
#else
s = "rb+";
#endif
break;
case file_mode::append:
#ifdef BOOST_MSVC
s = L"ab";
#else
s = "ab";
#endif
break;
case file_mode::append_existing:
{
#ifdef BOOST_MSVC
std::FILE* f0;
auto const ev =
::_wfopen_s(&f0, unicode_path.c_str(), L"rb+");
if(ev)
{
ec.assign(ev, generic_category());
return;
}
#else
auto const f0 =
std::fopen(path, "rb+");
if(! f0)
{
ec.assign(errno, generic_category());
return;
}
#endif
std::fclose(f0);
#ifdef BOOST_MSVC
s = L"ab";
#else
s = "ab";
#endif
break;
}
}
#ifdef BOOST_MSVC
auto const ev = ::_wfopen_s(&f_, unicode_path.c_str(), s);
if(ev)
{
f_ = nullptr;
ec.assign(ev, generic_category());
return;
}
#else
f_ = std::fopen(path, s);
if(! f_)
{
ec.assign(errno, generic_category());
return;
}
#endif
}
std::uint64_t
file_stdio::
size(error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
int result = std::fseek(f_, 0, SEEK_END);
if(result != 0)
{
ec.assign(errno, generic_category());
return 0;
}
long size = std::ftell(f_);
if(size == -1L)
{
ec.assign(errno, generic_category());
std::fseek(f_, pos, SEEK_SET);
return 0;
}
result = std::fseek(f_, pos, SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec = {};
return size;
}
std::uint64_t
file_stdio::
pos(error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
ec = {};
return pos;
}
void
file_stdio::
seek(std::uint64_t offset, error_code& ec)
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
if(offset > static_cast<std::uint64_t>((std::numeric_limits<long>::max)()))
{
ec = make_error_code(errc::invalid_seek);
return;
}
int result = std::fseek(f_,
static_cast<long>(offset), SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec = {};
}
std::size_t
file_stdio::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nread = std::fread(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nread;
}
std::size_t
file_stdio::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nwritten = std::fwrite(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nwritten;
}
} // beast
} // boost
#endif