From 5a0f7888f368330fa80e5cd648a576c0a4eb04f7 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 30 Jun 2023 10:36:27 +0200 Subject: * added file sharing control to BasicFile (required to implement lockfiles) * added delete-on-close support to BasicFile * added BasicFile::ReadRange() --- src/zenutil/basicfile.cpp | 55 +++++++++++++++++++++++++-------- src/zenutil/include/zenutil/basicfile.h | 24 ++++++++++---- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/zenutil/basicfile.cpp b/src/zenutil/basicfile.cpp index 22acc346f..f91a54222 100644 --- a/src/zenutil/basicfile.cpp +++ b/src/zenutil/basicfile.cpp @@ -36,15 +36,17 @@ BasicFile::Open(const std::filesystem::path& FileName, Mode Mode) if (Ec) { - throw std::system_error(Ec, fmt::format("failed to open file '{}'", FileName)); + 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 Mode, std::error_code& Ec) +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; @@ -72,17 +74,18 @@ BasicFile::Open(const std::filesystem::path& FileName, Mode Mode, std::error_cod break; } - const DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; - HANDLE hTemplateFile = nullptr; - - HANDLE FileHandle = CreateFile(FileName.c_str(), - dwDesiredAccess, - dwShareMode, - /* lpSecurityAttributes */ nullptr, - dwCreationDisposition, - dwFlagsAndAttributes, - hTemplateFile); + 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 | (EnumHasAllFlags(InMode, Mode::kDeleteOnClose) ? FILE_FLAG_DELETE_ON_CLOSE : 0); + const HANDLE hTemplateFile = nullptr; + const HANDLE FileHandle = CreateFile(FileName.c_str(), + dwDesiredAccess, + dwShareMode, + /* lpSecurityAttributes */ nullptr, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile); if (FileHandle == INVALID_HANDLE_VALUE) { @@ -139,6 +142,12 @@ BasicFile::Close() } } +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) { @@ -220,6 +229,26 @@ BasicFile::StreamByteRange(uint64_t FileOffset, uint64_t Size, std::function + +#include +#include #include #include @@ -36,25 +40,31 @@ public: kTruncate = 2, // Opens (or creates) a file for read and write and sets the size to zero kDelete = 3, // Opens (or creates) a file for read and write allowing .DeleteFile file disposition to be set kTruncateDelete = - 4 // Opens (or creates) a file for read and write and sets the size to zero allowing .DeleteFile file disposition to be set + 4, // Opens (or creates) a file for read and write and sets the size to zero allowing .DeleteFile file disposition to be set + kModeMask = 0x0007, + kPreventDelete = 0x1000'0000, // Do not open with delete sharing mode (prevent other processes from deleting file while open) + kPreventWrite = 0x2000'0000, // Do not open with write sharing mode (prevent other processes from writing to file while open) + kDeleteOnClose = 0x4000'0000, // File should be deleted when the last handle is closed }; void Open(const std::filesystem::path& FileName, Mode Mode); void Open(const std::filesystem::path& FileName, Mode Mode, std::error_code& Ec); void Close(); void Read(void* Data, uint64_t Size, uint64_t FileOffset); + IoBuffer ReadRange(uint64_t FileOffset, uint64_t ByteCount); void StreamFile(std::function&& ChunkFun); void StreamByteRange(uint64_t FileOffset, uint64_t Size, std::function&& ChunkFun); void Write(MemoryView Data, uint64_t FileOffset); void Write(MemoryView Data, uint64_t FileOffset, std::error_code& Ec); + uint64_t Write(CompositeBuffer Data, uint64_t FileOffset, std::error_code& Ec); void Write(const void* Data, uint64_t Size, uint64_t FileOffset); void Write(const void* Data, uint64_t Size, uint64_t FileOffset, std::error_code& Ec); void Flush(); - uint64_t FileSize(); - void SetFileSize(uint64_t FileSize); - IoBuffer ReadAll(); - void WriteAll(IoBuffer Data, std::error_code& Ec); - void* Detach(); + [[nodiscard]] uint64_t FileSize(); + void SetFileSize(uint64_t FileSize); + IoBuffer ReadAll(); + void WriteAll(IoBuffer Data, std::error_code& Ec); + void* Detach(); inline void* Handle() { return m_FileHandle; } @@ -63,6 +73,8 @@ protected: private: }; +ENUM_CLASS_FLAGS(BasicFile::Mode); + /** * Simple abstraction for a temporary file * -- cgit v1.2.3