Files
rippled/include/nudb/impl/win32_file.ipp
Vinnie Falco 79159ffd87 Squashed 'src/nudb/' content from commit 00adc6a
git-subtree-dir: src/nudb
git-subtree-split: 00adc6a4f16679a376f40c967f77dfa544c179c1
2016-09-29 19:24:12 -04:00

265 lines
5.4 KiB
C++

//
// 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 NUDB_IMPL_WIN32_FILE_IPP
#define NUDB_IMPL_WIN32_FILE_IPP
#include <boost/assert.hpp>
namespace nudb {
inline
win32_file::
~win32_file()
{
close();
}
inline
win32_file::
win32_file(win32_file&& other)
: hf_(other.hf_)
{
other.hf_ = INVALID_HANDLE_VALUE;
}
inline
win32_file&
win32_file::
operator=(win32_file&& other)
{
if(&other == this)
return *this;
close();
hf_ = other.hf_;
other.hf_ = INVALID_HANDLE_VALUE;
return *this;
}
inline
void
win32_file::
close()
{
if(hf_ != INVALID_HANDLE_VALUE)
{
::CloseHandle(hf_);
hf_ = INVALID_HANDLE_VALUE;
}
}
inline
void
win32_file::
create(file_mode mode, path_type const& path, error_code& ec)
{
BOOST_ASSERT(! is_open());
auto const f = flags(mode);
hf_ = ::CreateFileA(path.c_str(),
f.first,
0,
NULL,
CREATE_NEW,
f.second,
NULL);
if(hf_ == INVALID_HANDLE_VALUE)
return last_err(ec);
}
inline
void
win32_file::
open(file_mode mode, path_type const& path, error_code& ec)
{
BOOST_ASSERT(! is_open());
auto const f = flags(mode);
hf_ = ::CreateFileA(path.c_str(),
f.first,
0,
NULL,
OPEN_EXISTING,
f.second,
NULL);
if(hf_ == INVALID_HANDLE_VALUE)
return last_err(ec);
}
inline
void
win32_file::
erase(path_type const& path, error_code& ec)
{
BOOL const bSuccess =
::DeleteFileA(path.c_str());
if(! bSuccess)
return last_err(ec);
}
inline
std::uint64_t
win32_file::
size(error_code& ec) const
{
BOOST_ASSERT(is_open());
LARGE_INTEGER fileSize;
if(! ::GetFileSizeEx(hf_, &fileSize))
{
last_err(ec);
return 0;
}
return fileSize.QuadPart;
}
inline
void
win32_file::
read(std::uint64_t offset, void* buffer, std::size_t bytes, error_code& ec)
{
while(bytes > 0)
{
DWORD bytesRead;
LARGE_INTEGER li;
li.QuadPart = static_cast<LONGLONG>(offset);
OVERLAPPED ov;
ov.Offset = li.LowPart;
ov.OffsetHigh = li.HighPart;
ov.hEvent = NULL;
DWORD amount;
if(bytes > std::numeric_limits<DWORD>::max())
amount = std::numeric_limits<DWORD>::max();
else
amount = static_cast<DWORD>(bytes);
BOOL const bSuccess = ::ReadFile(
hf_, buffer, amount, &bytesRead, &ov);
if(! bSuccess)
{
DWORD const dwError = ::GetLastError();
if(dwError != ERROR_HANDLE_EOF)
return err(dwError, ec);
ec = make_error_code(error::short_read);
return;
}
if(bytesRead == 0)
{
ec = make_error_code(error::short_read);
return;
}
offset += bytesRead;
bytes -= bytesRead;
buffer = reinterpret_cast<char*>(
buffer) + bytesRead;
}
}
inline
void
win32_file::
write(std::uint64_t offset,
void const* buffer, std::size_t bytes, error_code& ec)
{
while(bytes > 0)
{
LARGE_INTEGER li;
li.QuadPart = static_cast<LONGLONG>(offset);
OVERLAPPED ov;
ov.Offset = li.LowPart;
ov.OffsetHigh = li.HighPart;
ov.hEvent = NULL;
DWORD amount;
if(bytes > std::numeric_limits<DWORD>::max())
amount = std::numeric_limits<DWORD>::max();
else
amount = static_cast<DWORD>(bytes);
DWORD bytesWritten;
BOOL const bSuccess = ::WriteFile(
hf_, buffer, amount, &bytesWritten, &ov);
if(! bSuccess)
return last_err(ec);
if(bytesWritten == 0)
{
ec = error_code{errc::no_space_on_device,
generic_category()};;
return;
}
offset += bytesWritten;
bytes -= bytesWritten;
buffer = reinterpret_cast<char const*>(
buffer) + bytesWritten;
}
}
inline
void
win32_file::
sync(error_code& ec)
{
if(! ::FlushFileBuffers(hf_))
return last_err(ec);
}
inline
void
win32_file::
trunc(std::uint64_t length, error_code& ec)
{
LARGE_INTEGER li;
li.QuadPart = length;
BOOL bSuccess;
bSuccess = ::SetFilePointerEx(
hf_, li, NULL, FILE_BEGIN);
if(bSuccess)
bSuccess = ::SetEndOfFile(hf_);
if(! bSuccess)
return last_err(ec);
}
inline
std::pair<DWORD, DWORD>
win32_file::
flags(file_mode mode)
{
std::pair<DWORD, DWORD> result{0, 0};
switch(mode)
{
case file_mode::scan:
result.first =
GENERIC_READ;
result.second =
FILE_FLAG_SEQUENTIAL_SCAN;
break;
case file_mode::read:
result.first =
GENERIC_READ;
result.second =
FILE_FLAG_RANDOM_ACCESS;
break;
case file_mode::append:
result.first =
GENERIC_READ | GENERIC_WRITE;
result.second =
FILE_FLAG_RANDOM_ACCESS
//| FILE_FLAG_NO_BUFFERING
//| FILE_FLAG_WRITE_THROUGH
;
break;
case file_mode::write:
result.first =
GENERIC_READ | GENERIC_WRITE;
result.second =
FILE_FLAG_RANDOM_ACCESS;
break;
}
return result;
}
} // nudb
#endif