1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00

local-store: Fix potential race in build log creation

Add atomic counter to temporary log file names and retry loop to
handle EEXIST errors. If another process creates the log file first,
we gracefully exit since the log already exists.
This commit is contained in:
Jörg Thalheim 2025-06-12 17:40:54 +02:00
parent 975b2c2edd
commit bc73faf88f

View file

@ -24,6 +24,7 @@
#include <algorithm>
#include <cstring>
#include <atomic>
#include <memory>
#include <new>
#include <sys/types.h>
@ -1666,11 +1667,35 @@ void LocalStore::addBuildLog(const StorePath & drvPath, std::string_view log)
createDirs(dirOf(logPath));
auto tmpFile = fmt("%s.tmp.%d", logPath, getpid());
/* Retry loop for temporary log file creation to handle race conditions */
while (true) {
auto tmpFile = makeTempPath(dirOf(logPath), baseNameOf(logPath) + ".tmp");
writeFile(tmpFile, compress("bzip2", log));
try {
writeFile(tmpFile, compress("bzip2", log));
} catch (Error & e) {
e.addTrace({}, "writing build log to '%s'", tmpFile);
throw;
}
std::filesystem::rename(tmpFile, logPath);
try {
std::filesystem::rename(tmpFile, logPath);
break; /* Success! */
} catch (std::filesystem::filesystem_error & e) {
try {
std::filesystem::remove(tmpFile);
} catch (...) {
/* Ignore errors removing the temp file */
}
if (e.code() == std::errc::file_exists) {
/* Another process created the log file. That's fine, we're done. */
break;
}
throw SysError("renaming temporary file '%1%' to '%2%'", tmpFile, logPath);
}
}
}
std::optional<std::string> LocalStore::getVersion()