diff options
Diffstat (limited to 'zenstore/basicfile.cpp')
| -rw-r--r-- | zenstore/basicfile.cpp | 123 |
1 files changed, 106 insertions, 17 deletions
diff --git a/zenstore/basicfile.cpp b/zenstore/basicfile.cpp index 35ccdd042..fe54184cf 100644 --- a/zenstore/basicfile.cpp +++ b/zenstore/basicfile.cpp @@ -5,6 +5,8 @@ #include <zencore/except.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> +#include <zencore/testing.h> +#include <zencore/testutils.h> #include <fmt/format.h> #include <gsl/gsl-lite.hpp> @@ -13,16 +15,54 @@ namespace zen { using namespace fmt::literals; +BasicFile::~BasicFile() +{ + Close(); +} + +void +BasicFile::Open(std::filesystem::path FileName, bool IsCreate) +{ + std::error_code Ec; + Open(FileName, IsCreate, Ec); + + if (Ec) + { + throw std::system_error(Ec, "failed to open file '{}'"_format(FileName)); + } +} + void -BasicFile::Open(std::filesystem::path FileName, bool isCreate) +BasicFile::Open(std::filesystem::path FileName, bool IsCreate, std::error_code& Ec) { - const DWORD dwCreationDisposition = isCreate ? CREATE_ALWAYS : OPEN_EXISTING; + const DWORD dwCreationDisposition = IsCreate ? CREATE_ALWAYS : OPEN_EXISTING; + const DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + const DWORD dwShareMode = FILE_SHARE_READ; + const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + HANDLE hTemplateFile = nullptr; + + HANDLE FileHandle = CreateFile(FileName.c_str(), + dwDesiredAccess, + dwShareMode, + /* lpSecurityAttributes */ nullptr, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile); + + if (FileHandle == INVALID_HANDLE_VALUE) + { + Ec = zen::MakeErrorCodeFromLastError(); + } - HRESULT hRes = m_File.Create(FileName.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, dwCreationDisposition); + m_FileHandle = FileHandle; +} - if (FAILED(hRes)) +void +BasicFile::Close() +{ + if (m_FileHandle) { - ThrowSystemException(hRes, "Failed to open bucket sobs file '{}'"_format(FileName)); + ::CloseHandle(m_FileHandle); } } @@ -34,11 +74,14 @@ BasicFile::Read(void* Data, uint64_t Size, uint64_t Offset) Ovl.Offset = DWORD(Offset & 0xffff'ffffu); Ovl.OffsetHigh = DWORD(Offset >> 32); - HRESULT hRes = m_File.Read(Data, gsl::narrow<DWORD>(Size), &Ovl); + DWORD dwNumberOfBytesToRead = gsl::narrow<DWORD>(Size); + DWORD dwNumberOfBytesRead = 0; + + BOOL Success = ::ReadFile(m_FileHandle, Data, dwNumberOfBytesToRead, &dwNumberOfBytesRead, &Ovl); - if (FAILED(hRes)) + if (!Success) { - ThrowSystemException(hRes, "Failed to read from file '{}'"_format(zen::PathFromHandle(m_File))); + ThrowLastError("Failed to read from file '{}'"_format(zen::PathFromHandle(m_FileHandle))); } } @@ -53,6 +96,35 @@ BasicFile::ReadAll() } void +BasicFile::StreamFile(std::function<void(const void* Data, uint64_t Size)>&& ChunkFun) +{ + StreamByteRange(0, FileSize(), std::move(ChunkFun)); +} + +void +BasicFile::StreamByteRange(uint64_t FileOffset, uint64_t Size, std::function<void(const void* Data, uint64_t Size)>&& ChunkFun) +{ + const uint64_t ChunkSize = 128 * 1024; + IoBuffer ReadBuffer{ChunkSize}; + void* BufferPtr = ReadBuffer.MutableData(); + + uint64_t RemainBytes = Size; + uint64_t CurrentOffset = FileOffset; + + while (RemainBytes) + { + const uint64_t ThisChunkBytes = zen::Min(ChunkSize, RemainBytes); + + Read(BufferPtr, ThisChunkBytes, CurrentOffset); + + ChunkFun(BufferPtr, ThisChunkBytes); + + CurrentOffset += ThisChunkBytes; + RemainBytes -= ThisChunkBytes; + } +} + +void BasicFile::Write(const void* Data, uint64_t Size, uint64_t Offset) { OVERLAPPED Ovl{}; @@ -60,33 +132,50 @@ BasicFile::Write(const void* Data, uint64_t Size, uint64_t Offset) Ovl.Offset = DWORD(Offset & 0xffff'ffffu); Ovl.OffsetHigh = DWORD(Offset >> 32); - HRESULT hRes = m_File.Write(Data, gsl::narrow<DWORD>(Size), &Ovl); + DWORD dwNumberOfBytesToWrite = gsl::narrow<DWORD>(Size); + DWORD dwNumberOfBytesWritten = 0; + + BOOL Success = ::WriteFile(m_FileHandle, Data, dwNumberOfBytesToWrite, &dwNumberOfBytesWritten, &Ovl); - if (FAILED(hRes)) + if (!Success) { - ThrowSystemException(hRes, "Failed to write to file '{}'"_format(zen::PathFromHandle(m_File))); + ThrowLastError("Failed to write to file '{}'"_format(zen::PathFromHandle(m_FileHandle))); } } void BasicFile::Flush() { - m_File.Flush(); + FlushFileBuffers(m_FileHandle); } uint64_t BasicFile::FileSize() { - ULONGLONG Sz; - m_File.GetSize(Sz); + ULARGE_INTEGER liFileSize; + liFileSize.LowPart = ::GetFileSize(m_FileHandle, &liFileSize.HighPart); + + return uint64_t(liFileSize.QuadPart); +} + +#if ZEN_WITH_TESTS + +TEST_CASE("BasicFile") +{ + ScopedCurrentDirectoryChange _; - return uint64_t(Sz); + BasicFile File1; + CHECK_THROWS(File1.Open("zonk", false)); + CHECK_NOTHROW(File1.Open("zonk", true)); + CHECK_NOTHROW(File1.Write("abcd", 4, 0)); + CHECK(File1.FileSize() == 4); } void -BasicFile::Close() +basicfile_forcelink() { - m_File.Close(); } +#endif + } // namespace zen |