diff options
Diffstat (limited to 'src/zenutil/basicfile.cpp')
| -rw-r--r-- | src/zenutil/basicfile.cpp | 1033 |
1 files changed, 0 insertions, 1033 deletions
diff --git a/src/zenutil/basicfile.cpp b/src/zenutil/basicfile.cpp deleted file mode 100644 index 391c150c6..000000000 --- a/src/zenutil/basicfile.cpp +++ /dev/null @@ -1,1033 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "zenutil/basicfile.h" - -#include <zencore/compactbinary.h> -#include <zencore/except.h> -#include <zencore/filesystem.h> -#include <zencore/fmtutils.h> -#include <zencore/memory/memory.h> -#include <zencore/testing.h> -#include <zencore/testutils.h> - -#if ZEN_PLATFORM_WINDOWS -# include <zencore/windows.h> -#else -# include <fcntl.h> -# include <sys/file.h> -# include <sys/stat.h> -# include <unistd.h> -#endif - -#include <fmt/format.h> -#include <gsl/gsl-lite.hpp> - -namespace zen { - -BasicFile::~BasicFile() -{ - Close(); -} - -void -BasicFile::Open(const std::filesystem::path& FileName, Mode Mode) -{ - std::error_code Ec; - Open(FileName, Mode, Ec); - - if (Ec) - { - throw std::system_error(Ec, fmt::format("failed to open file '{}', mode: {:x}", FileName, uint32_t(Mode))); - } -} - -void -BasicFile::Open(const std::filesystem::path& FileName, Mode InMode, std::error_code& Ec) -{ - Ec.clear(); - - Mode Mode = InMode & Mode::kModeMask; - -#if ZEN_PLATFORM_WINDOWS - DWORD dwCreationDisposition = 0; - DWORD dwDesiredAccess = 0; - switch (Mode) - { - case Mode::kRead: - dwCreationDisposition |= OPEN_EXISTING; - dwDesiredAccess |= GENERIC_READ; - break; - case Mode::kWrite: - dwCreationDisposition |= OPEN_ALWAYS; - dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE); - break; - case Mode::kDelete: - dwCreationDisposition |= OPEN_ALWAYS; - dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE | DELETE); - break; - case Mode::kTruncate: - dwCreationDisposition |= CREATE_ALWAYS; - dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE); - break; - case Mode::kTruncateDelete: - dwCreationDisposition |= CREATE_ALWAYS; - dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE | DELETE); - break; - } - - const DWORD dwShareMode = FILE_SHARE_READ | (EnumHasAllFlags(InMode, Mode::kPreventWrite) ? 0 : FILE_SHARE_WRITE) | - (EnumHasAllFlags(InMode, Mode::kPreventDelete) ? 0 : FILE_SHARE_DELETE); - const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; - const HANDLE hTemplateFile = nullptr; - const HANDLE FileHandle = CreateFile(FileName.c_str(), - dwDesiredAccess, - dwShareMode, - /* lpSecurityAttributes */ nullptr, - dwCreationDisposition, - dwFlagsAndAttributes, - hTemplateFile); - - if (FileHandle == INVALID_HANDLE_VALUE) - { - Ec = MakeErrorCodeFromLastError(); - - return; - } -#else - int OpenFlags = O_CLOEXEC; - switch (Mode) - { - case Mode::kRead: - OpenFlags |= O_RDONLY; - break; - case Mode::kWrite: - case Mode::kDelete: - OpenFlags |= (O_RDWR | O_CREAT); - break; - case Mode::kTruncate: - case Mode::kTruncateDelete: - OpenFlags |= (O_RDWR | O_CREAT | O_TRUNC); - break; - } - - int Fd = open(FileName.c_str(), OpenFlags, 0666); - if (Fd < 0) - { - Ec = MakeErrorCodeFromLastError(); - return; - } - if (Mode != Mode::kRead) - { - fchmod(Fd, 0666); - } - - void* FileHandle = (void*)(uintptr_t(Fd)); -#endif - - m_FileHandle = FileHandle; -} - -void -BasicFile::Open(const std::filesystem::path& FileName, Mode Mode, std::function<bool(std::error_code& Ec)>&& RetryCallback) -{ - std::error_code Ec; - Open(FileName, Mode, Ec); - while (Ec && RetryCallback(Ec)) - { - Ec.clear(); - Open(FileName, Mode, Ec); - } - if (Ec) - { - throw std::system_error(Ec, fmt::format("failed to open file '{}', mode: {:x}", FileName, uint32_t(Mode))); - } -} - -void -BasicFile::Close() -{ - if (m_FileHandle) - { -#if ZEN_PLATFORM_WINDOWS - ::CloseHandle(m_FileHandle); -#else - int Fd = int(uintptr_t(m_FileHandle)); - close(Fd); -#endif - m_FileHandle = nullptr; - } -} - -IoBuffer -BasicFile::ReadRange(uint64_t FileOffset, uint64_t ByteCount) -{ - return IoBufferBuilder::MakeFromFileHandle(m_FileHandle, FileOffset, ByteCount); -} - -void -BasicFile::Read(void* Data, uint64_t BytesToRead, uint64_t FileOffset) -{ - const uint64_t MaxChunkSize = 2u * 1024 * 1024 * 1024; - - while (BytesToRead) - { - const uint64_t NumberOfBytesToRead = Min(BytesToRead, MaxChunkSize); - int32_t Error = 0; - size_t BytesRead = 0; - -#if ZEN_PLATFORM_WINDOWS - OVERLAPPED Ovl{}; - - Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(FileOffset >> 32); - - DWORD dwNumberOfBytesRead = 0; - BOOL Success = ::ReadFile(m_FileHandle, Data, DWORD(NumberOfBytesToRead), &dwNumberOfBytesRead, &Ovl); - if (Success) - { - BytesRead = size_t(dwNumberOfBytesRead); - } - else - { - Error = zen::GetLastError(); - } -#else - static_assert(sizeof(off_t) >= sizeof(uint64_t), "sizeof(off_t) does not support large files"); - int Fd = int(uintptr_t(m_FileHandle)); - ssize_t ReadResult = pread(Fd, Data, NumberOfBytesToRead, FileOffset); - if (ReadResult != -1) - { - BytesRead = size_t(ReadResult); - } - else - { - Error = zen::GetLastError(); - } -#endif - - if (Error || (BytesRead != NumberOfBytesToRead)) - { - std::error_code DummyEc; - throw std::system_error(std::error_code(Error, std::system_category()), - fmt::format("ReadFile/pread failed (offset {:#x}, size {:#x}) file: '{}' (size {:#x})", - FileOffset, - NumberOfBytesToRead, - PathFromHandle(m_FileHandle, DummyEc), - FileSizeFromHandle(m_FileHandle))); - } - - BytesToRead -= NumberOfBytesToRead; - FileOffset += NumberOfBytesToRead; - Data = reinterpret_cast<uint8_t*>(Data) + NumberOfBytesToRead; - } -} - -IoBuffer -BasicFile::ReadAll() -{ - if (const uint64_t Size = FileSize()) - { - IoBuffer Buffer(Size); - Read(Buffer.MutableData(), Size, 0); - return Buffer; - } - else - { - return {}; - } -} - -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; - } -} - -uint64_t -BasicFile::Write(CompositeBuffer Data, uint64_t FileOffset, std::error_code& Ec) -{ - uint64_t WrittenBytes = 0; - for (const SharedBuffer& Buffer : Data.GetSegments()) - { - MemoryView BlockView = Buffer.GetView(); - Write(BlockView, FileOffset + WrittenBytes, Ec); - - if (Ec) - { - return WrittenBytes; - } - - WrittenBytes += BlockView.GetSize(); - } - - return WrittenBytes; -} - -void -BasicFile::Write(MemoryView Data, uint64_t FileOffset, std::error_code& Ec) -{ - Write(Data.GetData(), Data.GetSize(), FileOffset, Ec); -} - -void -BasicFile::Write(const void* Data, uint64_t Size, uint64_t FileOffset, std::error_code& Ec) -{ - Ec.clear(); - - const uint64_t MaxChunkSize = 2u * 1024 * 1024 * 1024; - - while (Size) - { - const uint64_t NumberOfBytesToWrite = Min(Size, MaxChunkSize); - -#if ZEN_PLATFORM_WINDOWS - OVERLAPPED Ovl{}; - - Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(FileOffset >> 32); - - DWORD dwNumberOfBytesWritten = 0; - - BOOL Success = ::WriteFile(m_FileHandle, Data, DWORD(NumberOfBytesToWrite), &dwNumberOfBytesWritten, &Ovl); -#else - static_assert(sizeof(off_t) >= sizeof(uint64_t), "sizeof(off_t) does not support large files"); - int Fd = int(uintptr_t(m_FileHandle)); - int BytesWritten = pwrite(Fd, Data, NumberOfBytesToWrite, FileOffset); - bool Success = (BytesWritten > 0); -#endif - - if (!Success) - { - Ec = MakeErrorCodeFromLastError(); - - return; - } - - Size -= NumberOfBytesToWrite; - FileOffset += NumberOfBytesToWrite; - Data = reinterpret_cast<const uint8_t*>(Data) + NumberOfBytesToWrite; - } -} - -void -BasicFile::Write(MemoryView Data, uint64_t FileOffset) -{ - Write(Data.GetData(), Data.GetSize(), FileOffset); -} - -void -BasicFile::Write(const void* Data, uint64_t Size, uint64_t Offset) -{ - std::error_code Ec; - Write(Data, Size, Offset, Ec); - - if (Ec) - { - std::error_code Dummy; - throw std::system_error(Ec, fmt::format("Failed to write to file '{}'", zen::PathFromHandle(m_FileHandle, Dummy))); - } -} - -void -BasicFile::WriteAll(IoBuffer Data, std::error_code& Ec) -{ - Write(Data.Data(), Data.Size(), 0, Ec); -} - -void -BasicFile::Flush() -{ - if (m_FileHandle == nullptr) - { - return; - } -#if ZEN_PLATFORM_WINDOWS - FlushFileBuffers(m_FileHandle); -#else - int Fd = int(uintptr_t(m_FileHandle)); - fsync(Fd); -#endif -} - -uint64_t -BasicFile::FileSize() const -{ -#if ZEN_PLATFORM_WINDOWS - ULARGE_INTEGER liFileSize; - liFileSize.LowPart = ::GetFileSize(m_FileHandle, &liFileSize.HighPart); - if (liFileSize.LowPart == INVALID_FILE_SIZE) - { - int Error = zen::GetLastError(); - if (Error) - { - std::error_code Dummy; - ThrowSystemError(Error, fmt::format("Failed to get file size from file '{}'", PathFromHandle(m_FileHandle, Dummy))); - } - } - return uint64_t(liFileSize.QuadPart); -#else - int Fd = int(uintptr_t(m_FileHandle)); - static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); - struct stat Stat; - if (fstat(Fd, &Stat) == -1) - { - std::error_code Dummy; - ThrowSystemError(GetLastError(), fmt::format("Failed to get file size from file '{}'", PathFromHandle(m_FileHandle, Dummy))); - } - return uint64_t(Stat.st_size); -#endif -} - -uint64_t -BasicFile::FileSize(std::error_code& Ec) const -{ -#if ZEN_PLATFORM_WINDOWS - ULARGE_INTEGER liFileSize; - liFileSize.LowPart = ::GetFileSize(m_FileHandle, &liFileSize.HighPart); - if (liFileSize.LowPart == INVALID_FILE_SIZE) - { - int Error = zen::GetLastError(); - if (Error) - { - Ec = MakeErrorCode(Error); - return 0; - } - } - return uint64_t(liFileSize.QuadPart); -#else - int Fd = int(uintptr_t(m_FileHandle)); - static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); - struct stat Stat; - if (fstat(Fd, &Stat) == -1) - { - Ec = MakeErrorCodeFromLastError(); - return 0; - } - return uint64_t(Stat.st_size); -#endif -} - -void -BasicFile::SetFileSize(uint64_t FileSize) -{ -#if ZEN_PLATFORM_WINDOWS - LARGE_INTEGER liFileSize; - liFileSize.QuadPart = FileSize; - BOOL OK = ::SetFilePointerEx(m_FileHandle, liFileSize, 0, FILE_BEGIN); - if (OK == FALSE) - { - int Error = zen::GetLastError(); - if (Error) - { - std::error_code Dummy; - ThrowSystemError(Error, - fmt::format("Failed to set file pointer to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy))); - } - } - OK = ::SetEndOfFile(m_FileHandle); - if (OK == FALSE) - { - int Error = zen::GetLastError(); - if (Error) - { - std::error_code Dummy; - ThrowSystemError(Error, - fmt::format("Failed to set end of file to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy))); - } - } -#elif ZEN_PLATFORM_MAC - int Fd = int(intptr_t(m_FileHandle)); - if (ftruncate(Fd, (off_t)FileSize) < 0) - { - int Error = zen::GetLastError(); - if (Error) - { - std::error_code Dummy; - ThrowSystemError(Error, - fmt::format("Failed to set truncate file to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy))); - } - } -#else - int Fd = int(intptr_t(m_FileHandle)); - if (ftruncate64(Fd, (off64_t)FileSize) < 0) - { - int Error = zen::GetLastError(); - if (Error) - { - std::error_code Dummy; - ThrowSystemError(Error, - fmt::format("Failed to set truncate file to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy))); - } - } - if (FileSize > 0) - { - int Error = posix_fallocate64(Fd, 0, (off64_t)FileSize); - if (Error) - { - std::error_code Dummy; - ThrowSystemError(Error, - fmt::format("Failed to allocate space of {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy))); - } - } -#endif -} - -void -BasicFile::Attach(void* Handle) -{ - ZEN_ASSERT(Handle != nullptr); - ZEN_ASSERT(m_FileHandle == nullptr); - m_FileHandle = Handle; -} - -void* -BasicFile::Detach() -{ - void* FileHandle = m_FileHandle; - m_FileHandle = 0; - return FileHandle; -} - -////////////////////////////////////////////////////////////////////////// - -TemporaryFile::~TemporaryFile() -{ - Close(); -} - -void -TemporaryFile::Close() -{ - if (m_FileHandle) - { -#if ZEN_PLATFORM_WINDOWS - // Mark file for deletion when final handle is closed - - FILE_DISPOSITION_INFO Fdi{.DeleteFile = TRUE}; - - SetFileInformationByHandle(m_FileHandle, FileDispositionInfo, &Fdi, sizeof Fdi); -#else - std::error_code Ec; - std::filesystem::path FilePath = zen::PathFromHandle(m_FileHandle, Ec); - if (!Ec) - { - unlink(FilePath.c_str()); - } -#endif - - BasicFile::Close(); - } -} - -void -TemporaryFile::CreateTemporary(std::filesystem::path TempDirName, std::error_code& Ec) -{ - StringBuilder<64> TempName; - Oid::NewOid().ToString(TempName); - - m_TempPath = TempDirName / TempName.c_str(); - - Open(m_TempPath, BasicFile::Mode::kTruncateDelete, Ec); -} - -void -TemporaryFile::MoveTemporaryIntoPlace(std::filesystem::path FinalFileName, std::error_code& Ec) -{ - // We intentionally call the base class Close() since otherwise we'll end up - // deleting the temporary file - BasicFile::Close(); - - std::filesystem::rename(m_TempPath, FinalFileName, Ec); - - if (Ec) - { - // Try to re-open the temp file so we clean up after us when TemporaryFile is destructed - std::error_code DummyEc; - Open(m_TempPath, BasicFile::Mode::kWrite, DummyEc); - } -} - -////////////////////////////////////////////////////////////////////////// - -void -TemporaryFile::SafeWriteFile(const std::filesystem::path& Path, MemoryView Data) -{ - TemporaryFile TempFile; - std::error_code Ec; - SafeWriteFile(Path, Data, Ec); - if (Ec) - { - throw std::system_error(Ec, fmt::format("Failed to safely write file '{}'", Path)); - } -} - -void -TemporaryFile::SafeWriteFile(const std::filesystem::path& Path, MemoryView Data, std::error_code& OutEc) -{ - TemporaryFile TempFile; - if (TempFile.CreateTemporary(Path.parent_path(), OutEc); !OutEc) - { - if (TempFile.Write(Data, 0, OutEc); !OutEc) - { - TempFile.MoveTemporaryIntoPlace(Path, OutEc); - } - } -} - -////////////////////////////////////////////////////////////////////////// - -LockFile::LockFile() -{ -} - -LockFile::~LockFile() -{ -#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC - int Fd = int(intptr_t(m_FileHandle)); - flock(Fd, LOCK_UN | LOCK_NB); -#endif -} - -void -LockFile::Create(std::filesystem::path FileName, CbObject Payload, std::error_code& Ec) -{ -#if ZEN_PLATFORM_WINDOWS - Ec.clear(); - - const DWORD dwCreationDisposition = CREATE_ALWAYS; - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | DELETE; - const DWORD dwShareMode = FILE_SHARE_READ; - const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE; - HANDLE hTemplateFile = nullptr; - - HANDLE FileHandle = CreateFile(FileName.c_str(), - dwDesiredAccess, - dwShareMode, - /* lpSecurityAttributes */ nullptr, - dwCreationDisposition, - dwFlagsAndAttributes, - hTemplateFile); - - if (FileHandle == INVALID_HANDLE_VALUE) - { - Ec = zen::MakeErrorCodeFromLastError(); - - return; - } -#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC - int Fd = open(FileName.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666); - if (Fd < 0) - { - Ec = zen::MakeErrorCodeFromLastError(); - return; - } - fchmod(Fd, 0666); - - int LockRet = flock(Fd, LOCK_EX | LOCK_NB); - if (LockRet < 0) - { - Ec = zen::MakeErrorCodeFromLastError(); - close(Fd); - return; - } - - void* FileHandle = (void*)uintptr_t(Fd); -#endif - - m_FileHandle = FileHandle; - - BasicFile::Write(Payload.GetBuffer(), 0, Ec); -} - -void -LockFile::Update(CbObject Payload, std::error_code& Ec) -{ - BasicFile::Write(Payload.GetBuffer(), 0, Ec); -} - -////////////////////////////////////////////////////////////////////////// - -BasicFileBuffer::BasicFileBuffer(BasicFile& Base, uint64_t BufferSize) -: m_Base(Base) -, m_Buffer(nullptr) -, m_BufferSize(BufferSize) -, m_Size(Base.FileSize()) -, m_BufferStart(0) -, m_BufferEnd(0) -{ - m_Buffer = (uint8_t*)Memory::Alloc(m_BufferSize); -} - -BasicFileBuffer::~BasicFileBuffer() -{ - Memory::Free(m_Buffer); -} - -void -BasicFileBuffer::Read(void* Data, uint64_t Size, uint64_t FileOffset) -{ - if (m_Buffer == nullptr || (Size > m_BufferSize) || (FileOffset + Size > m_Size)) - { - m_Base.Read(Data, Size, FileOffset); - return; - } - uint8_t* WritePtr = ((uint8_t*)Data); - uint64_t Begin = FileOffset; - uint64_t End = FileOffset + Size; - if (FileOffset <= m_BufferStart) - { - if (End > m_BufferStart) - { - uint64_t Count = Min(m_BufferEnd, End) - m_BufferStart; - memcpy(WritePtr + End - Count - FileOffset, m_Buffer, Count); - End -= Count; - if (Begin == End) - { - return; - } - } - } - else if (FileOffset < m_BufferEnd) - { - uint64_t Count = Min(m_BufferEnd, End) - FileOffset; - memcpy(WritePtr + Begin - FileOffset, m_Buffer + Begin - m_BufferStart, Count); - Begin += Count; - if (Begin == End) - { - return; - } - } - m_BufferStart = Begin; - m_BufferEnd = Min(Begin + m_BufferSize, m_Size); - m_Base.Read(m_Buffer, m_BufferEnd - m_BufferStart, m_BufferStart); - uint64_t Count = Min(m_BufferEnd, End) - m_BufferStart; - memcpy(WritePtr + Begin - FileOffset, m_Buffer, Count); - ZEN_ASSERT(Begin + Count == End); -} - -MemoryView -BasicFileBuffer::MakeView(uint64_t Size, uint64_t FileOffset) -{ - if (FileOffset < m_BufferStart || (FileOffset + Size) > m_BufferEnd) - { - if (m_Buffer == nullptr || (Size > m_BufferSize) || (FileOffset + Size > m_Size)) - { - return {}; - } - m_BufferStart = FileOffset; - m_BufferEnd = Min(m_BufferStart + m_BufferSize, m_Size); - m_Base.Read(m_Buffer, m_BufferEnd - m_BufferStart, m_BufferStart); - } - return MemoryView(m_Buffer + (FileOffset - m_BufferStart), Size); -} - -////////////////////////////////////////////////////////////////////////// - -BasicFileWriter::BasicFileWriter(BasicFile& Base, uint64_t BufferSize) -: m_Base(Base) -, m_Buffer(nullptr) -, m_BufferSize(BufferSize) -, m_BufferStart(0) -, m_BufferEnd(0) -{ - m_Buffer = (uint8_t*)Memory::Alloc(m_BufferSize); -} - -BasicFileWriter::~BasicFileWriter() -{ - Flush(); - Memory::Free(m_Buffer); -} - -void -BasicFileWriter::Write(const void* Data, uint64_t Size, uint64_t FileOffset) -{ - if (m_Buffer == nullptr || (Size >= m_BufferSize)) - { - m_Base.Write(Data, Size, FileOffset); - return; - } - - // Note that this only supports buffering of sequential writes! - - if (FileOffset != m_BufferEnd) - { - Flush(); - m_BufferStart = m_BufferEnd = FileOffset; - } - - const uint8_t* DataPtr = (const uint8_t*)Data; - while (Size) - { - const uint64_t RemainingBufferCapacity = m_BufferStart + m_BufferSize - m_BufferEnd; - const uint64_t BlockWriteBytes = Min(RemainingBufferCapacity, Size); - const uint64_t BufferWriteOffset = FileOffset - m_BufferStart; - - ZEN_ASSERT_SLOW(BufferWriteOffset < m_BufferSize); - ZEN_ASSERT_SLOW((BufferWriteOffset + BlockWriteBytes) <= m_BufferSize); - - memcpy(m_Buffer + BufferWriteOffset, DataPtr, BlockWriteBytes); - - Size -= BlockWriteBytes; - m_BufferEnd += BlockWriteBytes; - FileOffset += BlockWriteBytes; - DataPtr += BlockWriteBytes; - - if ((m_BufferEnd - m_BufferStart) == m_BufferSize) - { - Flush(); - } - } -} - -void -BasicFileWriter::Flush() -{ - const uint64_t BufferedBytes = m_BufferEnd - m_BufferStart; - - if (BufferedBytes == 0) - return; - - const uint64_t WriteOffset = m_BufferStart; - m_BufferStart = m_BufferEnd; - - m_Base.Write(m_Buffer, BufferedBytes, WriteOffset); -} - -////////////////////////////////////////////////////////////////////////// - -/* - ___________ __ - \__ ___/___ _______/ |_ ______ - | |_/ __ \ / ___/\ __\/ ___/ - | |\ ___/ \___ \ | | \___ \ - |____| \___ >____ > |__| /____ > - \/ \/ \/ -*/ - -#if ZEN_WITH_TESTS - -TEST_CASE("BasicFile") -{ - ScopedCurrentDirectoryChange _; - - BasicFile File1; - CHECK_THROWS(File1.Open("zonk", BasicFile::Mode::kRead)); - CHECK_NOTHROW(File1.Open("zonk", BasicFile::Mode::kTruncate)); - CHECK_NOTHROW(File1.Write("abcd", 4, 0)); - CHECK(File1.FileSize() == 4); - { - IoBuffer Data = File1.ReadAll(); - CHECK(Data.Size() == 4); - CHECK_EQ(memcmp(Data.Data(), "abcd", 4), 0); - } - CHECK_NOTHROW(File1.Write("efgh", 4, 2)); - CHECK(File1.FileSize() == 6); - { - IoBuffer Data = File1.ReadAll(); - CHECK(Data.Size() == 6); - CHECK_EQ(memcmp(Data.Data(), "abefgh", 6), 0); - } -} - -TEST_CASE("TemporaryFile") -{ - ScopedCurrentDirectoryChange _; - - SUBCASE("DeleteOnClose") - { - std::filesystem::path Path; - { - TemporaryFile TmpFile; - std::error_code Ec; - TmpFile.CreateTemporary(std::filesystem::current_path(), Ec); - CHECK(!Ec); - Path = TmpFile.GetPath(); - CHECK(std::filesystem::exists(Path)); - } - CHECK(std::filesystem::exists(Path) == false); - } - - SUBCASE("MoveIntoPlace") - { - TemporaryFile TmpFile; - std::error_code Ec; - TmpFile.CreateTemporary(std::filesystem::current_path(), Ec); - CHECK(!Ec); - std::filesystem::path TempPath = TmpFile.GetPath(); - std::filesystem::path FinalPath = std::filesystem::current_path() / "final"; - CHECK(std::filesystem::exists(TempPath)); - TmpFile.MoveTemporaryIntoPlace(FinalPath, Ec); - CHECK(!Ec); - CHECK(std::filesystem::exists(TempPath) == false); - CHECK(std::filesystem::exists(FinalPath)); - } -} - -TEST_CASE("BasicFileBuffer") -{ - ScopedCurrentDirectoryChange _; - { - BasicFile File1; - const std::string_view Data = "0123456789abcdef"; - File1.Open("buffered", BasicFile::Mode::kTruncate); - for (uint32_t I = 0; I < 16; ++I) - { - File1.Write(Data.data(), Data.size(), I * Data.size()); - } - } - SUBCASE("EvenBuffer") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - // Non-primed - { - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 1 * 16); - std::string_view Verify(Buffer, 16); - CHECK(Verify == "0123456789abcdef"); - } - // Primed - { - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 1 * 16); - std::string_view Verify(Buffer, 16); - CHECK(Verify == "0123456789abcdef"); - } - } - SUBCASE("UnevenBuffer") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - // Non-primed - { - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 7); - std::string_view Verify(Buffer, 16); - CHECK(Verify == "789abcdef0123456"); - } - // Primed - { - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 7); - std::string_view Verify(Buffer, 16); - CHECK(Verify == "789abcdef0123456"); - } - } - SUBCASE("BiggerThanBuffer") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[17] = {0}; - File1Buffer.Read(Buffer, 17, 0 * 16); - std::string_view Verify(Buffer, 17); - CHECK(Verify == "0123456789abcdef0"); - } - SUBCASE("InsideBuffer") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 0 * 16); - - File1Buffer.Read(Buffer, 8, 2); - std::string_view Verify(Buffer, 8); - CHECK(Verify == "23456789"); - } - SUBCASE("BeginningOfBuffer") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 8); - - File1Buffer.Read(Buffer, 8, 8); - std::string_view Verify(Buffer, 8); - CHECK(Verify == "89abcdef"); - } - SUBCASE("EndOfBuffer") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 0 * 16); - - File1Buffer.Read(Buffer, 8, 8); - std::string_view Verify(Buffer, 8); - CHECK(Verify == "89abcdef"); - } - SUBCASE("OverEnd") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 0 * 16); - - File1Buffer.Read(Buffer, 16, 8); - std::string_view Verify(Buffer, 16); - CHECK(Verify == "89abcdef01234567"); - } - SUBCASE("OverBegin") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 1 * 16); - - File1Buffer.Read(Buffer, 16, 8); - std::string_view Verify(Buffer, 16); - CHECK(Verify == "89abcdef01234567"); - } - SUBCASE("EndOfFile") - { - BasicFile File1; - File1.Open("buffered", BasicFile::Mode::kRead); - BasicFileBuffer File1Buffer(File1, 16); - char Buffer[16] = {0}; - File1Buffer.Read(Buffer, 16, 0 * 16); - - File1Buffer.Read(Buffer, 8, 256 - 8); - std::string_view Verify(Buffer, 8); - CHECK(Verify == "89abcdef"); - } -} - -void -basicfile_forcelink() -{ -} - -#endif - -} // namespace zen |