diff options
| author | Stefan Boberg <[email protected]> | 2026-04-23 18:16:57 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2026-04-23 18:16:57 +0200 |
| commit | 0232b991cd7d8e3a2114ea30e4591dd3e7b65c36 (patch) | |
| tree | 94730e7594fd09ae1fa820391ce311f6daf13905 /src/zencore/basicfile.cpp | |
| parent | Fix forward declaration order for s_GotSigWinch and SigWinchHandler (diff) | |
| parent | trace: declare Region event name fields as AnsiString (#1012) (diff) | |
| download | archived-zen-sb/zen-help.tar.xz archived-zen-sb/zen-help.zip | |
Merge branch 'main' into sb/zen-helpsb/zen-help
- Combine HelpCommand (this branch) with HistoryCommand (main) in zen CLI dispatcher
- Keep filter-aware TuiPickOne rewrite; adopt main's ASCII arrow glyphs in doc comment
Diffstat (limited to 'src/zencore/basicfile.cpp')
| -rw-r--r-- | src/zencore/basicfile.cpp | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/src/zencore/basicfile.cpp b/src/zencore/basicfile.cpp index 9dcf7663a..fdf742261 100644 --- a/src/zencore/basicfile.cpp +++ b/src/zencore/basicfile.cpp @@ -3,6 +3,7 @@ #include <zencore/basicfile.h> #include <zencore/compactbinary.h> +#include <zencore/compactbinarybuilder.h> #include <zencore/except.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> @@ -608,6 +609,67 @@ LockFile::Update(CbObject Payload, std::error_code& Ec) BasicFile::Write(Payload.GetBuffer(), 0, Ec); } +bool +LockFile::IsHeldLive(const std::filesystem::path& FileName, bool AttemptCleanup) +{ +#if ZEN_PLATFORM_WINDOWS + if (AttemptCleanup) + { + if (DeleteFileW(FileName.c_str())) + { + return false; + } + const DWORD Err = ::GetLastError(); + if (Err == ERROR_FILE_NOT_FOUND || Err == ERROR_PATH_NOT_FOUND) + { + return false; + } + return true; + } + + HANDLE Handle = CreateFileW(FileName.c_str(), + DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr); + if (Handle != INVALID_HANDLE_VALUE) + { + CloseHandle(Handle); + return false; + } + const DWORD Err = ::GetLastError(); + if (Err == ERROR_FILE_NOT_FOUND || Err == ERROR_PATH_NOT_FOUND) + { + return false; + } + return true; +#else + int Fd = open(FileName.c_str(), O_RDONLY | O_CLOEXEC); + if (Fd < 0) + { + if (errno == ENOENT) + { + return false; + } + return true; + } + if (flock(Fd, LOCK_EX | LOCK_NB) == 0) + { + if (AttemptCleanup) + { + unlink(FileName.c_str()); + } + flock(Fd, LOCK_UN); + close(Fd); + return false; + } + close(Fd); + return true; +#endif +} + ////////////////////////////////////////////////////////////////////////// BasicFileBuffer::BasicFileBuffer(BasicFile& Base, uint64_t BufferSize) @@ -947,6 +1009,61 @@ TEST_CASE("TemporaryFile") } } +TEST_CASE("LockFile.IsHeldLive") +{ + ScopedCurrentDirectoryChange _; + const std::filesystem::path Path = std::filesystem::current_path() / "heldlive.lock"; + + SUBCASE("Nonexistent") + { + std::error_code Ec; + RemoveFile(Path, Ec); + CHECK(LockFile::IsHeldLive(Path, /*AttemptCleanup*/ true) == false); + CHECK(LockFile::IsHeldLive(Path, /*AttemptCleanup*/ false) == false); + CHECK(IsFile(Path) == false); + } + + SUBCASE("Live holder") + { + LockFile Lock; + std::error_code Ec; + Lock.Create(Path, CbObjectWriter().Save(), Ec); + CHECK(!Ec); + CHECK(IsFile(Path)); + + CHECK(LockFile::IsHeldLive(Path, /*AttemptCleanup*/ false) == true); + CHECK(IsFile(Path)); + CHECK(LockFile::IsHeldLive(Path, /*AttemptCleanup*/ true) == true); + CHECK(IsFile(Path)); + } + + SUBCASE("Stale file, cleanup") + { + { + BasicFile File; + File.Open(Path, BasicFile::Mode::kTruncate); + File.Write("x", 1, 0); + } + CHECK(IsFile(Path)); + CHECK(LockFile::IsHeldLive(Path, /*AttemptCleanup*/ true) == false); + CHECK(IsFile(Path) == false); + } + + SUBCASE("Stale file, no cleanup") + { + { + BasicFile File; + File.Open(Path, BasicFile::Mode::kTruncate); + File.Write("x", 1, 0); + } + CHECK(IsFile(Path)); + CHECK(LockFile::IsHeldLive(Path, /*AttemptCleanup*/ false) == false); + CHECK(IsFile(Path)); + std::error_code Ec; + RemoveFile(Path, Ec); + } +} + TEST_CASE("BasicFileBuffer") { ScopedCurrentDirectoryChange _; |