diff --git a/src/libutil/fs-sink.cc b/src/libutil/fs-sink.cc index 9058d6e00..45c0262e6 100644 --- a/src/libutil/fs-sink.cc +++ b/src/libutil/fs-sink.cc @@ -71,6 +71,29 @@ static std::filesystem::path append(const std::filesystem::path & src, const Can return dst; } +#ifndef _WIN32 +void RestoreSink::createDirectory(const CanonPath & path, DirectoryCreatedCallback callback) +{ + if (path.isRoot()) { + createDirectory(path); + callback(*this, path); + return; + } + + createDirectory(path); + assert(dirFd); // If that's not true the above call must have thrown an exception. + + RestoreSink dirSink{startFsync}; + dirSink.dstPath = append(dstPath, path); + dirSink.dirFd = ::openat(dirFd.get(), path.rel_c_str(), O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + + if (!dirSink.dirFd) + throw SysError("opening directory '%s'", dirSink.dstPath.string()); + + callback(dirSink, CanonPath::root); +} +#endif + void RestoreSink::createDirectory(const CanonPath & path) { auto p = append(dstPath, path); diff --git a/src/libutil/include/nix/util/fs-sink.hh b/src/libutil/include/nix/util/fs-sink.hh index b2b009b83..60e8441dd 100644 --- a/src/libutil/include/nix/util/fs-sink.hh +++ b/src/libutil/include/nix/util/fs-sink.hh @@ -120,6 +120,10 @@ struct RestoreSink : FileSystemObjectSink void createDirectory(const CanonPath & path) override; +#ifndef _WIN32 + void createDirectory(const CanonPath & path, DirectoryCreatedCallback callback) override; +#endif + void createRegularFile(const CanonPath & path, std::function) override; void createSymlink(const CanonPath & path, const std::string & target) override; diff --git a/tests/functional/nars.sh b/tests/functional/nars.sh index a52c257bc..2925177c5 100755 --- a/tests/functional/nars.sh +++ b/tests/functional/nars.sh @@ -114,7 +114,7 @@ if (( unicodeTestCode == 1 )); then # If the command failed (MacOS or ZFS + normalization), checks that it failed # with the expected "already exists" error, and that this is the same # behavior as `touch` - echo "$unicodeTestOut" | grepQuiet "path '.*/out/â' already exists" + echo "$unicodeTestOut" | grepQuiet "creating directory '.*/out/â': File exists" (( touchFilesCount == 1 )) elif (( unicodeTestCode == 0 )); then