diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc index 347e8a7..80566ea 100644 --- a/nix/libstore/local-store.cc +++ b/nix/libstore/local-store.cc @@ -1391,7 +1391,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name, StringSource source(dump); restorePath(dstPath, source); } else - writeFile(dstPath, dump); + writeFileAtomically(dstPath, dump); canonicalisePathMetaData(dstPath, -1); diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc index c077544..e33824b 100644 --- a/nix/libutil/util.cc +++ b/nix/libutil/util.cc @@ -272,6 +272,22 @@ void writeFile(const Path & path, const string & s) writeFull(fd, s); } +void writeFileAtomically(const Path & path, const string & s) +{ + auto tmpPath = path + ".tmp"; + AutoCloseFD fd = open(tmpPath.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666); + if (fd == -1) + throw SysError(format("opening file '%1%'") % tmpPath); + writeFull(fd, s); +#if _POSIX_SYNCHRONIZED_IO > 0 + if (fdatasync(fd) != 0) + throw SysError(format("flushing file '%1%'") % tmpPath); +#endif + fd.close(); + if (rename(tmpPath.c_str(), path.c_str()) != 0) + throw SysError(format("renaming '%1%' to '%2'") % tmpPath % path); +} + string readLine(int fd) { diff --git a/nix/libutil/util.hh b/nix/libutil/util.hh index e84d64d..829f90b 100644 --- a/nix/libutil/util.hh +++ b/nix/libutil/util.hh @@ -86,6 +86,9 @@ string readFile(const Path & path, bool drain = false); /* Write a string to a file. */ void writeFile(const Path & path, const string & s); +/* Same, but do it atomically. */ +void writeFileAtomically(const Path & path, const string & s); + /* Read a line from a file descriptor. */ string readLine(int fd);