aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/util.cc
diff options
context:
space:
mode:
authorsqualus <squalus@squalus.net>2022-09-19 11:15:31 -0700
committersqualus <squalus@squalus.net>2022-09-19 20:13:30 -0700
commit1b595026e18afb050de3f62ded8f7180bc8b2b0e (patch)
tree6a6c3834483a46ce194cd37bafb0a8168742148c /src/libutil/util.cc
parent9d860f34673fbf07a2cf07ff854ae6683dae2fb8 (diff)
Improve durability of schema version file writes
- call close explicitly in writeFile to prevent the close exception from being ignored - fsync after writing schema file to flush data to disk - fsync schema file parent to flush metadata to disk https://github.com/NixOS/nix/issues/7064
Diffstat (limited to 'src/libutil/util.cc')
-rw-r--r--src/libutil/util.cc38
1 files changed, 36 insertions, 2 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 96ac11ea2..623b74bdd 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -353,7 +353,7 @@ void readFile(const Path & path, Sink & sink)
}
-void writeFile(const Path & path, std::string_view s, mode_t mode)
+void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
@@ -364,10 +364,16 @@ void writeFile(const Path & path, std::string_view s, mode_t mode)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
+ if (sync)
+ fd.fsync();
+ // Explicitly close to make sure exceptions are propagated.
+ fd.close();
+ if (sync)
+ syncParent(path);
}
-void writeFile(const Path & path, Source & source, mode_t mode)
+void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
@@ -386,6 +392,20 @@ void writeFile(const Path & path, Source & source, mode_t mode)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
+ if (sync)
+ fd.fsync();
+ // Explicitly close to make sure exceptions are propagated.
+ fd.close();
+ if (sync)
+ syncParent(path);
+}
+
+void syncParent(const Path & path)
+{
+ AutoCloseFD fd = open(dirOf(path).c_str(), O_RDONLY, 0);
+ if (!fd)
+ throw SysError("opening file '%1%'", path);
+ fd.fsync();
}
std::string readLine(int fd)
@@ -841,6 +861,20 @@ void AutoCloseFD::close()
}
}
+void AutoCloseFD::fsync()
+{
+ if (fd != -1) {
+ int result;
+#if __APPLE__
+ result = ::fcntl(fd, F_FULLFSYNC);
+#else
+ result = ::fsync(fd);
+#endif
+ if (result == -1)
+ throw SysError("fsync file descriptor %1%", fd);
+ }
+}
+
AutoCloseFD::operator bool() const
{