From 2d836357dc69136aaa6db42be2e163732b413e68 Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Wed, 26 Mar 2025 01:06:03 +0100 Subject: [PATCH] libutil: writeFile variant for file descriptors `writeFile` lose its `sync` boolean flag to make things simpler. A new `writeFileAndSync` function is created and all call sites are converted to it. Change-Id: Ib871a5283a9c047db1e4fe48a241506e4aab9192 Signed-off-by: Raito Bezarius --- lix/libstore/local-store.cc | 4 +-- lix/libutil/file-system.cc | 50 ++++++++++++++++++++++++++----------- lix/libutil/file-system.hh | 22 ++++++++-------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/lix/libstore/local-store.cc b/lix/libstore/local-store.cc index 3d75be2f4..1d4ba8665 100644 --- a/lix/libstore/local-store.cc +++ b/lix/libstore/local-store.cc @@ -224,7 +224,7 @@ void LocalStore::initDB(DBState & state) else if (curSchema == 0) { /* new store */ curSchema = nixSchemaVersion; openDB(state, true); - writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true); + writeFileAndSync(schemaPath, fmt("%1%", nixSchemaVersion), 0666); } else if (curSchema < nixSchemaVersion) { @@ -277,7 +277,7 @@ void LocalStore::initDB(DBState & state) txn.commit(); } - writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true); + writeFileAndSync(schemaPath, fmt("%1%", nixSchemaVersion), 0666); lockFile(globalLock.get(), ltRead, always_progresses); } diff --git a/lix/libutil/file-system.cc b/lix/libutil/file-system.cc index 47fc2f7ba..0fe70d938 100644 --- a/lix/libutil/file-system.cc +++ b/lix/libutil/file-system.cc @@ -358,28 +358,49 @@ Generator readFileSource(const Path & path) }(std::move(fd)); } -void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync, bool allowInterrupts) +void writeFile(const Path & path, std::string_view s, mode_t mode, bool allowInterrupts) { AutoCloseFD fd{open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode)}; if (!fd) throw SysError("opening file '%1%'", path); + + writeFile(fd, s, mode, allowInterrupts); + + /* Close explicitly to propagate the exceptions. */ + fd.close(); +} + +void writeFile(AutoCloseFD & fd, std::string_view s, mode_t mode, bool allowInterrupts) +{ + assert(fd); try { writeFull(fd.get(), s, allowInterrupts); } catch (Error & e) { - e.addTrace({}, "writing file '%1%'", path); + e.addTrace({}, "writing file '%1%'", fd.guessOrInventPath()); throw; } - if (sync) - fd.fsync(); - // Explicitly close to make sure exceptions are propagated. - fd.close(); - if (sync) - syncParent(path); } -void writeFileUninterruptible(const Path & path, std::string_view s, mode_t mode, bool sync) +void writeFileUninterruptible(const Path & path, std::string_view s, mode_t mode) { - writeFile(path, s, mode, sync, false); + writeFile(path, s, mode, false); +} + +void writeFileAndSync(const Path & path, std::string_view s, mode_t mode) +{ + { + AutoCloseFD fd{open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode)}; + if (!fd) { + throw SysError("opening file '%1%'", path); + } + + writeFile(fd, s, mode); + fd.fsync(); + /* Close explicitly to ensure that exceptions are propagated. */ + fd.close(); + } + + syncParent(path); } static AutoCloseFD openForWrite(const Path & path, mode_t mode) @@ -400,7 +421,7 @@ static void closeForWrite(const Path & path, AutoCloseFD & fd, bool sync) syncParent(path); } -void writeFile(const Path & path, Source & source, mode_t mode, bool sync) +void writeFile(const Path & path, Source & source, mode_t mode) { AutoCloseFD fd = openForWrite(path, mode); @@ -417,11 +438,10 @@ void writeFile(const Path & path, Source & source, mode_t mode, bool sync) e.addTrace({}, "writing file '%1%'", path); throw; } - closeForWrite(path, fd, sync); + closeForWrite(path, fd, false); } -kj::Promise> -writeFile(const Path & path, AsyncInputStream & source, mode_t mode, bool sync) +kj::Promise> writeFile(const Path & path, AsyncInputStream & source, mode_t mode) try { AutoCloseFD fd = openForWrite(path, mode); @@ -439,7 +459,7 @@ try { e.addTrace({}, "writing file '%1%'", path); throw; } - closeForWrite(path, fd, sync); + closeForWrite(path, fd, false); co_return result::success(); } catch (...) { co_return result::current_exception(); diff --git a/lix/libutil/file-system.hh b/lix/libutil/file-system.hh index 7d76b4fd0..8b9100bdc 100644 --- a/lix/libutil/file-system.hh +++ b/lix/libutil/file-system.hh @@ -190,19 +190,21 @@ Generator readFileSource(const Path & path); * Write a string to a file. */ void writeFile( - const Path & path, - std::string_view s, - mode_t mode = 0666, - bool sync = false, - bool allowInterrupts = true -); -void writeFileUninterruptible( - const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false + const Path & path, std::string_view s, mode_t mode = 0666, bool allowInterrupts = true ); +void writeFileUninterruptible(const Path & path, std::string_view s, mode_t mode = 0666); +void writeFile(const Path & path, Source & source, mode_t mode = 0666); -void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false); +void writeFile( + AutoCloseFD & fd, std::string_view s, mode_t mode = 0666, bool allowInterrupts = true +); kj::Promise> -writeFile(const Path & path, AsyncInputStream & source, mode_t mode = 0666, bool sync = false); +writeFile(const Path & path, AsyncInputStream & source, mode_t mode = 0666); + +/** + * Write a string to a file and flush the file and its parents direcotry to disk. + */ +void writeFileAndSync(const Path & path, std::string_view s, mode_t mode = 0666); /** * Flush a file's parent directory to disk