diff options
| author | Stefan Boberg <[email protected]> | 2021-09-25 21:21:16 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-25 21:21:16 +0200 |
| commit | e96d3f99687cdd57d6d2b342b465928c72e84c27 (patch) | |
| tree | 0f34da12a34c7dddac09eca6281e1d29e815182e /zenstore/basicfile.cpp | |
| parent | Ensure FILE_RENAME_INFO structure allocation is freed also if FileCasStrategy... (diff) | |
| download | zen-e96d3f99687cdd57d6d2b342b465928c72e84c27.tar.xz zen-e96d3f99687cdd57d6d2b342b465928c72e84c27.zip | |
Added TemporaryFile implementation, provides a simple abstraction around temporary files
Diffstat (limited to 'zenstore/basicfile.cpp')
| -rw-r--r-- | zenstore/basicfile.cpp | 84 |
1 files changed, 83 insertions, 1 deletions
diff --git a/zenstore/basicfile.cpp b/zenstore/basicfile.cpp index fe54184cf..233efa11c 100644 --- a/zenstore/basicfile.cpp +++ b/zenstore/basicfile.cpp @@ -36,11 +36,16 @@ void BasicFile::Open(std::filesystem::path FileName, bool IsCreate, std::error_code& Ec) { const DWORD dwCreationDisposition = IsCreate ? CREATE_ALWAYS : OPEN_EXISTING; - const DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; const DWORD dwShareMode = FILE_SHARE_READ; const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; HANDLE hTemplateFile = nullptr; + if (IsCreate) + { + dwDesiredAccess |= DELETE; + } + HANDLE FileHandle = CreateFile(FileName.c_str(), dwDesiredAccess, dwShareMode, @@ -63,6 +68,7 @@ BasicFile::Close() if (m_FileHandle) { ::CloseHandle(m_FileHandle); + m_FileHandle = nullptr; } } @@ -158,6 +164,51 @@ BasicFile::FileSize() return uint64_t(liFileSize.QuadPart); } +////////////////////////////////////////////////////////////////////////// + +TemporaryFile::~TemporaryFile() +{ + Close(); +} + +void +TemporaryFile::Close() +{ + if (m_FileHandle) + { + // Mark file for deletion when final handle is closed + + FILE_DISPOSITION_INFO Fdi{.DeleteFile = TRUE}; + + SetFileInformationByHandle(m_FileHandle, FileDispositionInfo, &Fdi, sizeof Fdi); + + 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(); + + const bool IsCreate = true; + + Open(m_TempPath, IsCreate, 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 ZEN_WITH_TESTS TEST_CASE("BasicFile") @@ -171,6 +222,37 @@ TEST_CASE("BasicFile") CHECK(File1.FileSize() == 4); } +TEST_CASE("TemporaryFile") +{ + ScopedCurrentDirectoryChange _; + + SUBCASE("DeleteOnClose") + { + TemporaryFile TmpFile; + std::error_code Ec; + TmpFile.CreateTemporary(std::filesystem::current_path(), Ec); + CHECK(!Ec); + CHECK(std::filesystem::exists(TmpFile.GetPath())); + TmpFile.Close(); + CHECK(std::filesystem::exists(TmpFile.GetPath()) == 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)); + } +} + void basicfile_forcelink() { |