mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +02:00
indirect-root-store: Fix race condition in makeSymlink
Replace rand() with atomic counter and add retry loop to handle race conditions when creating temporary symlinks for garbage collector roots.
This commit is contained in:
parent
ef05a2fa0f
commit
975b2c2edd
1 changed files with 26 additions and 5 deletions
|
@ -1,4 +1,5 @@
|
|||
#include "nix/store/indirect-root-store.hh"
|
||||
#include "nix/util/file-system.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -7,12 +8,32 @@ void IndirectRootStore::makeSymlink(const Path & link, const Path & target)
|
|||
/* Create directories up to `gcRoot'. */
|
||||
createDirs(dirOf(link));
|
||||
|
||||
/* Create the new symlink. */
|
||||
Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), rand());
|
||||
createSymlink(target, tempLink);
|
||||
/* Retry loop for temporary symlink creation to handle race conditions */
|
||||
while (true) {
|
||||
Path tempLink = makeTempPath(dirOf(link), baseNameOf(link) + ".tmp");
|
||||
|
||||
/* Atomically replace the old one. */
|
||||
std::filesystem::rename(tempLink, link);
|
||||
createSymlink(target, tempLink);
|
||||
|
||||
/* Atomically replace the old one. */
|
||||
try {
|
||||
std::filesystem::rename(tempLink, link);
|
||||
break; /* Success! */
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
try {
|
||||
std::filesystem::remove(tempLink);
|
||||
} catch (...) {
|
||||
/* Ignore errors removing the temp link */
|
||||
}
|
||||
|
||||
if (e.code() == std::errc::file_exists) {
|
||||
/* Race condition: another process created the same temp link.
|
||||
Try again with a different name. */
|
||||
continue;
|
||||
}
|
||||
|
||||
throw SysError("failed to create symlink '%1%' -> '%2%'", link, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue