From 545f5fb309e9ff8ce13c585671e5aae0bbcfc31d Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Sat, 10 Jan 2026 02:40:48 +0300 Subject: [PATCH] libstore: Use race-free copyRecursive with makeFSSourceAccessor and RestoreSink when copying FOD outputs --- src/libstore/unix/build/derivation-builder.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index b305d7d55..c318cd868 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -1703,10 +1703,18 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() [&](const DerivationOutput::CAFixed & dof) { auto & wanted = dof.ca.hash; - // Replace the output by a fresh copy of itself to make sure - // that there's no stale file descriptor pointing to it + /* Replace the output by a fresh copy of itself to make sure + that there's no stale file descriptor pointing to it. + IMPORTANT: Copying and deletion must be done in a race-free manner, thus + we are using the source accessor and sink here, since they are implemented + the most robustly. DO NOT USE copyFile here. */ + std::filesystem::path tmpOutput = actualPath.native() + ".tmp"; - copyFile(actualPath, tmpOutput, true); + auto accessor = makeFSSourceAccessor(actualPath); + auto copySink = RestoreSink(/*startFsync=*/settings.fsyncStorePaths); + copySink.dstPath = tmpOutput; + copyRecursive(*accessor, /*sourcePath=*/CanonPath::root, copySink, /*destPath=*/CanonPath::root); + deletePath(actualPath); std::filesystem::rename(tmpOutput, actualPath);