From 3f733a1cabba3f62f402ccefcc3a92a66fdc008b Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Wed, 25 Dec 2024 02:41:20 +0100 Subject: [PATCH] fix: ignore symlinks in fsync-store-paths Fixes: https://github.com/NixOS/nix/issues/12099 (cherry picked from commit 4a91e627a7617cc3d654967358fd29df076ab853) # Conflicts: # src/libutil/file-system.cc --- src/libutil/file-system.cc | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc index 732e0a327..56d84c382 100644 --- a/src/libutil/file-system.cc +++ b/src/libutil/file-system.cc @@ -318,6 +318,54 @@ void syncParent(const Path & path) } +<<<<<<< HEAD +======= +void recursiveSync(const Path & path) +{ + /* If it's a file or symlink, just fsync and return. */ + auto st = lstat(path); + if (S_ISREG(st.st_mode)) { + AutoCloseFD fd = toDescriptor(open(path.c_str(), O_RDONLY, 0)); + if (!fd) + throw SysError("opening file '%1%'", path); + fd.fsync(); + return; + } else if (S_ISLNK(st.st_mode)) + return; + + /* Otherwise, perform a depth-first traversal of the directory and + fsync all the files. */ + std::deque dirsToEnumerate; + dirsToEnumerate.push_back(path); + std::vector dirsToFsync; + while (!dirsToEnumerate.empty()) { + auto currentDir = dirsToEnumerate.back(); + dirsToEnumerate.pop_back(); + for (auto & entry : std::filesystem::directory_iterator(currentDir)) { + auto st = entry.symlink_status(); + if (fs::is_directory(st)) { + dirsToEnumerate.emplace_back(entry.path()); + } else if (fs::is_regular_file(st)) { + AutoCloseFD fd = toDescriptor(open(entry.path().string().c_str(), O_RDONLY, 0)); + if (!fd) + throw SysError("opening file '%1%'", entry.path()); + fd.fsync(); + } + } + dirsToFsync.emplace_back(std::move(currentDir)); + } + + /* Fsync all the directories. */ + for (auto dir = dirsToFsync.rbegin(); dir != dirsToFsync.rend(); ++dir) { + AutoCloseFD fd = toDescriptor(open(dir->string().c_str(), O_RDONLY, 0)); + if (!fd) + throw SysError("opening directory '%1%'", *dir); + fd.fsync(); + } +} + + +>>>>>>> 4a91e627a (fix: ignore symlinks in fsync-store-paths) static void _deletePath(Descriptor parentfd, const fs::path & path, uint64_t & bytesFreed) { #ifndef _WIN32