diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index c702df8f039..83945ae136c 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -560,7 +560,7 @@ ProcessLineResult NixRepl::processLine(std::string line) auto localStore = state->store.dynamic_pointer_cast(); if (localStore && command == ":bl") { std::string symlink = "repl-result-" + outputName; - localStore->addPermRoot(outputPath, absPath(symlink).string()); + localStore->addPermRoot(outputPath, absPath(symlink)); logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath)); } else { logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath)); diff --git a/src/libfetchers/git-lfs-fetch.cc b/src/libfetchers/git-lfs-fetch.cc index ac42493da03..4585e68e58e 100644 --- a/src/libfetchers/git-lfs-fetch.cc +++ b/src/libfetchers/git-lfs-fetch.cc @@ -61,26 +61,27 @@ static LfsApiInfo getLfsApi(const ParsedURL & url) auto args = getNixSshOpts(); if (url.authority->port) - args.push_back(fmt("-p%d", *url.authority->port)); + args.push_back(string_to_os_string(fmt("-p%d", *url.authority->port))); std::ostringstream hostnameAndUser; if (url.authority->user) hostnameAndUser << *url.authority->user << "@"; hostnameAndUser << url.authority->host; - args.push_back(std::move(hostnameAndUser).str()); + args.push_back(string_to_os_string(std::move(hostnameAndUser).str())); - args.push_back("--"); - args.push_back("git-lfs-authenticate"); + args.push_back(OS_STR("--")); + args.push_back(OS_STR("git-lfs-authenticate")); // FIXME %2F encode slashes? Does this command take/accept percent encoding? - args.push_back(url.renderPath(/*encode=*/false)); - args.push_back("download"); + args.push_back(string_to_os_string(url.renderPath(/*encode=*/false))); + args.push_back(OS_STR("download")); - auto [status, output] = runProgram({.program = "ssh", .args = toOsStrings(args)}); + auto [status, output] = runProgram({.program = "ssh", .args = args}); if (output.empty()) throw Error( "git-lfs-authenticate: no output (cmd: 'ssh %s')", - concatMapStringsSep(" ", args, escapeShellArgAlways)); + concatMapStringsSep( + " ", args, [](const OsString & s) { return escapeShellArgAlways(os_string_to_string(s)); })); auto queryResp = nlohmann::json::parse(output); auto headerIt = queryResp.find("header"); diff --git a/src/libflake-c/nix_api_flake_internal.hh b/src/libflake-c/nix_api_flake_internal.hh index fbc6574d68a..e048a47d333 100644 --- a/src/libflake-c/nix_api_flake_internal.hh +++ b/src/libflake-c/nix_api_flake_internal.hh @@ -13,7 +13,7 @@ struct nix_flake_settings struct nix_flake_reference_parse_flags { - std::optional baseDirectory; + std::optional baseDirectory; }; struct nix_flake_reference diff --git a/src/libstore-c/nix_api_store.cc b/src/libstore-c/nix_api_store.cc index eec7f34e8f1..fbb3c418566 100644 --- a/src/libstore-c/nix_api_store.cc +++ b/src/libstore-c/nix_api_store.cc @@ -116,7 +116,7 @@ nix_err nix_store_real_path( context->last_err_code = NIX_OK; try { auto store2 = store->ptr.dynamic_pointer_cast(); - auto res = store2 ? store2->toRealPath(path->path) : store->ptr->printStorePath(path->path); + auto res = store2 ? store2->toRealPath(path->path).string() : store->ptr->printStorePath(path->path); return call_nix_get_string_callback(res, callback, user_data); } NIXC_CATCH_ERRS diff --git a/src/libstore-tests/machines.cc b/src/libstore-tests/machines.cc index 1c4a6aab15c..f0a334c1b61 100644 --- a/src/libstore-tests/machines.cc +++ b/src/libstore-tests/machines.cc @@ -27,7 +27,7 @@ TEST(machines, getMachinesUriOnly) ASSERT_THAT(actual, SizeIs(1)); EXPECT_THAT(actual[0], Field(&Machine::storeUri, Eq(StoreReference::parse("ssh://nix@scratchy.labs.cs.uu.nl")))); EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("TEST_ARCH-TEST_OS"))); - EXPECT_THAT(actual[0], Field(&Machine::sshKey, SizeIs(0))); + EXPECT_THAT(actual[0], Field(&Machine::sshKey, Eq(std::filesystem::path{}))); EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(1))); EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(1))); EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, SizeIs(0))); @@ -49,7 +49,7 @@ TEST(machines, getMachinesDefaults) ASSERT_THAT(actual, SizeIs(1)); EXPECT_THAT(actual[0], Field(&Machine::storeUri, Eq(StoreReference::parse("ssh://nix@scratchy.labs.cs.uu.nl")))); EXPECT_THAT(actual[0], Field(&Machine::systemTypes, ElementsAre("TEST_ARCH-TEST_OS"))); - EXPECT_THAT(actual[0], Field(&Machine::sshKey, SizeIs(0))); + EXPECT_THAT(actual[0], Field(&Machine::sshKey, Eq(std::filesystem::path{}))); EXPECT_THAT(actual[0], Field(&Machine::maxJobs, Eq(1))); EXPECT_THAT(actual[0], Field(&Machine::speedFactor, Eq(1))); EXPECT_THAT(actual[0], Field(&Machine::supportedFeatures, SizeIs(0))); diff --git a/src/libstore-tests/nar-info-disk-cache.cc b/src/libstore-tests/nar-info-disk-cache.cc index 1e61dcc34a8..aebefc77567 100644 --- a/src/libstore-tests/nar-info-disk-cache.cc +++ b/src/libstore-tests/nar-info-disk-cache.cc @@ -26,7 +26,7 @@ TEST(NarInfoDiskCacheImpl, create_and_read) { auto cache = NarInfoDiskCache::getTest( - settings.getNarInfoDiskCacheSettings(), {.useWAL = settings.useSQLiteWAL}, dbPath.string()); + settings.getNarInfoDiskCacheSettings(), {.useWAL = settings.useSQLiteWAL}, dbPath); // Set up "background noise" and check that different caches receive different ids { @@ -76,7 +76,7 @@ TEST(NarInfoDiskCacheImpl, create_and_read) // We can't clear the in-memory cache, so we use a new cache object. This is // more realistic anyway. auto cache2 = NarInfoDiskCache::getTest( - settings.getNarInfoDiskCacheSettings(), {.useWAL = settings.useSQLiteWAL}, dbPath.string()); + settings.getNarInfoDiskCacheSettings(), {.useWAL = settings.useSQLiteWAL}, dbPath); { auto r = cache2->upToDateCacheExists("http://foo"); diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index 34dfac672e2..3618b5b3363 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -27,12 +27,12 @@ namespace nix { BinaryCacheStore::BinaryCacheStore(Config & config) : config{config} { - if (config.secretKeyFile != "") + if (!config.secretKeyFile.get().empty()) signers.push_back(std::make_unique(SecretKey{readFile(config.secretKeyFile.get())})); if (config.secretKeyFiles != "") { std::stringstream ss(config.secretKeyFiles); - Path keyPath; + std::string keyPath; while (std::getline(ss, keyPath, ',')) { signers.push_back(std::make_unique(SecretKey{readFile(keyPath)})); } diff --git a/src/libstore/build/derivation-building-goal.cc b/src/libstore/build/derivation-building-goal.cc index 24f4e0120a2..5a4e0076bce 100644 --- a/src/libstore/build/derivation-building-goal.cc +++ b/src/libstore/build/derivation-building-goal.cc @@ -387,8 +387,11 @@ Goal::Co DerivationBuildingGoal::tryToBuild(StorePathSet inputPaths) for (auto & i : drv->outputsAndOptPaths(worker.store)) { if (i.second.second) lockFiles.insert(localStore->toRealPath(*i.second.second)); - else - lockFiles.insert(localStore->toRealPath(drvPath) + "." + i.first); + else { + auto lockPath = localStore->toRealPath(drvPath); + lockPath += "." + i.first; + lockFiles.insert(std::move(lockPath)); + } } } diff --git a/src/libstore/builtins/buildenv.cc b/src/libstore/builtins/buildenv.cc index 514a3f3a38e..65b36f2552c 100644 --- a/src/libstore/builtins/buildenv.cc +++ b/src/libstore/builtins/buildenv.cc @@ -20,14 +20,15 @@ namespace { struct State { - std::map priorities; + std::map priorities; unsigned long symlinks = 0; }; } // namespace /* For each activated package, create symlinks */ -static void createLinks(State & state, const Path & srcDir, const Path & dstDir, int priority) +static void +createLinks(State & state, const std::filesystem::path & srcDir, const std::filesystem::path & dstDir, int priority) { DirectoryIterator srcFiles; @@ -35,7 +36,7 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir, srcFiles = DirectoryIterator{srcDir}; } catch (SystemError & e) { if (e.is(std::errc::not_a_directory)) { - warn("not including '%s' in the user environment because it's not a directory", srcDir); + warn("not including %s in the user environment because it's not a directory", PathFmt(srcDir)); return; } throw; @@ -76,11 +77,14 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir, createLinks(state, srcFile, dstFile, priority); continue; } else if (S_ISLNK(dstSt.st_mode)) { - auto target = canonPath(dstFile, true).string(); + auto target = canonPath(dstFile, true); if (!S_ISDIR(lstat(target).st_mode)) throw Error("collision between %1% and non-directory %2%", PathFmt(srcFile), PathFmt(target)); - if (unlink(dstFile.c_str()) == -1) - throw SysError("unlinking %1%", PathFmt(dstFile)); + try { + std::filesystem::remove(dstFile); + } catch (std::filesystem::filesystem_error & e) { + throw SystemError(e.code(), "unlinking %s", PathFmt(dstFile)); + } if (mkdir( dstFile.c_str() #ifndef _WIN32 // TODO abstract mkdir perms for Windows @@ -104,11 +108,14 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir, if (S_ISLNK(dstSt.st_mode)) { auto prevPriority = state.priorities[dstFile]; if (prevPriority == priority) - throw BuildEnvFileConflictError(readLink(dstFile).string(), srcFile, priority); + throw BuildEnvFileConflictError(readLink(dstFile), srcFile, priority); if (prevPriority < priority) continue; - if (unlink(dstFile.c_str()) == -1) - throw SysError("unlinking %1%", PathFmt(dstFile)); + try { + std::filesystem::remove(dstFile); + } catch (std::filesystem::filesystem_error & e) { + throw SystemError(e.code(), "unlinking %s", PathFmt(dstFile)); + } } else if (S_ISDIR(dstSt.st_mode)) throw Error("collision between non-directory '%1%' and directory '%2%'", srcFile, dstFile); } @@ -120,20 +127,20 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir, } } -void buildProfile(const Path & out, Packages && pkgs) +void buildProfile(const std::filesystem::path & out, Packages && pkgs) { State state; PathSet done, postponed; - auto addPkg = [&](const Path & pkgDir, int priority) { - if (!done.insert(pkgDir).second) + auto addPkg = [&](const std::filesystem::path & pkgDir, int priority) { + if (!done.insert(pkgDir.string()).second) return; createLinks(state, pkgDir, out, priority); try { for (const auto & p : tokenizeString>( - readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n")) + readFile(pkgDir / "nix-support" / "propagated-user-env-packages"), " \n")) if (!done.count(p)) postponed.insert(p); } catch (SystemError & e) { diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index 4d10d336210..3e5eac51700 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -680,17 +680,17 @@ static void performOp( "you are not privileged to create perm roots\n\n" "hint: you can just do this client-side without special privileges, and probably want to do that instead."); auto storePath = WorkerProto::Serialise::read(*store, rconn); - Path gcRoot = absPath(readString(conn.from)).string(); + std::filesystem::path gcRoot = absPath(readString(conn.from)); logger->startWork(); auto & localFSStore = require(*store); localFSStore.addPermRoot(storePath, gcRoot); logger->stopWork(); - conn.to << gcRoot; + conn.to << gcRoot.string(); break; } case WorkerProto::Op::AddIndirectRoot: { - Path path = absPath(readString(conn.from)).string(); + std::filesystem::path path = absPath(readString(conn.from)); logger->startWork(); auto & indirectRootStore = require(*store); diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index d644b3c6070..2039c2b4120 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -38,10 +38,10 @@ namespace nix { static std::string gcSocketPath = "gc-socket/socket"; static std::string gcRootsDir = "gcroots"; -void LocalStore::addIndirectRoot(const Path & path) +void LocalStore::addIndirectRoot(const std::filesystem::path & path) { - std::string hash = hashString(HashAlgorithm::SHA1, path).to_string(HashFormat::Nix32, false); - Path realRoot = canonPath((config->stateDir.get() / gcRootsDir / "auto" / hash).string()).string(); + std::string hash = hashString(HashAlgorithm::SHA1, path.string()).to_string(HashFormat::Nix32, false); + auto realRoot = canonPath(config->stateDir.get() / gcRootsDir / "auto" / hash); makeSymlink(realRoot, path); } @@ -54,10 +54,13 @@ void LocalStore::createTempRootsFile() return; while (1) { - if (pathExists(fnTempRoots)) + if (pathExists(fnTempRoots)) { /* It *must* be stale, since there can be no two processes with the same pid. */ - unlink(fnTempRoots.string().c_str()); + /* The error code of std::filesystem::remove() is intentionally ignored. */ + std::error_code ec; + std::filesystem::remove(fnTempRoots, ec); + } *fdTempRoots = openLockFile(fnTempRoots, true); @@ -166,13 +169,13 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) // those to keep the directory alive. continue; } - Path path = i.path().string(); + auto path = i.path(); pid_t pid = std::stoi(name); - debug("reading temporary root file '%1%'", path); + debug("reading temporary root file %1%", PathFmt(path)); AutoCloseFD fd(toDescriptor(open( - path.c_str(), + path.string().c_str(), #ifndef _WIN32 O_CLOEXEC | #endif @@ -182,15 +185,17 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) /* It's okay if the file has disappeared. */ if (errno == ENOENT) continue; - throw SysError("opening temporary roots file '%1%'", path); + throw SysError("opening temporary roots file %1%", PathFmt(path)); } /* Try to acquire a write lock without blocking. This can only succeed if the owning process has died. In that case we don't care about its temporary roots. */ if (lockFile(fd.get(), ltWrite, false)) { - printInfo("removing stale temporary roots file '%1%'", path); - unlink(path.c_str()); + printInfo("removing stale temporary roots file %1%", PathFmt(path)); + /* The error code of std::filesystem::remove() is intentionally ignored. */ + std::error_code ec; + std::filesystem::remove(path, ec); writeFull(fd.get(), "d"); continue; } @@ -202,7 +207,7 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) std::string::size_type pos = 0, end; while ((end = contents.find((char) 0, pos)) != std::string::npos) { - Path root(contents, pos, end - pos); + auto root = std::string_view(contents).substr(pos, end - pos); debug("got temporary root '%s'", root); tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{temp:%d}", pid)); pos = end + 1; @@ -210,15 +215,15 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) } } -void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, Roots & roots) +void LocalStore::findRoots(const std::filesystem::path & path, std::filesystem::file_type type, Roots & roots) { - auto foundRoot = [&](const Path & path, const Path & target) { + auto foundRoot = [&](const std::filesystem::path & path, const std::filesystem::path & target) { try { - auto storePath = toStorePath(target).first; + auto storePath = toStorePath(target.string()).first; if (isValidPath(storePath)) - roots[std::move(storePath)].emplace(path); + roots[std::move(storePath)].emplace(path.string()); else - printInfo("skipping invalid root from '%1%' to '%2%'", path, target); + printInfo("skipping invalid root from %1% to %2%", PathFmt(path), PathFmt(target)); } catch (BadStorePath &) { } }; @@ -231,38 +236,40 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R if (type == std::filesystem::file_type::directory) { for (auto & i : DirectoryIterator{path}) { checkInterrupt(); - findRoots(i.path().string(), i.symlink_status().type(), roots); + findRoots(i.path(), i.symlink_status().type(), roots); } } else if (type == std::filesystem::file_type::symlink) { - Path target = readLink(path).string(); - if (isInStore(target)) + auto target = readLink(path); + if (isInStore(target.string())) foundRoot(path, target); /* Handle indirect roots. */ else { - auto parentPath = std::filesystem::path(path).parent_path(); - target = absPath(target, &parentPath).string(); + auto parentPath = path.parent_path(); + target = absPath(target, &parentPath); if (!pathExists(target)) { - if (isInDir(path, std::filesystem::path{config->stateDir.get()} / gcRootsDir / "auto")) { - printInfo("removing stale link from '%1%' to '%2%'", path, target); - unlink(path.c_str()); + if (isInDir(path, config->stateDir.get() / gcRootsDir / "auto")) { + printInfo("removing stale link from %1% to %2%", PathFmt(path), PathFmt(target)); + /* The error code of std::filesystem::remove() is intentionally ignored. */ + std::error_code ec; + std::filesystem::remove(path, ec); } } else { if (!std::filesystem::is_symlink(target)) return; - Path target2 = readLink(target).string(); - if (isInStore(target2)) + auto target2 = readLink(target); + if (isInStore(target2.string())) foundRoot(target, target2); } } } else if (type == std::filesystem::file_type::regular) { - auto storePath = maybeParseStorePath(storeDir + "/" + std::string(baseNameOf(path))); + auto storePath = maybeParseStorePath(storeDir + "/" + std::string(baseNameOf(path.string()))); if (storePath && isValidPath(*storePath)) - roots[std::move(*storePath)].emplace(path); + roots[std::move(*storePath)].emplace(path.string()); } } @@ -271,16 +278,16 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R /* We only ignore permanent failures. */ if (e.code() == std::errc::permission_denied || e.code() == std::errc::no_such_file_or_directory || e.code() == std::errc::not_a_directory) - printInfo("cannot read potential root '%1%'", path); + printInfo("cannot read potential root %1%", PathFmt(path)); else - throw SystemError(e.code(), "finding GC roots in '%1%'", path); + throw SystemError(e.code(), "finding GC roots in %1%", PathFmt(path)); } catch (SystemError & e) { /* We only ignore permanent failures. */ if (e.is(std::errc::permission_denied) || e.is(std::errc::no_such_file_or_directory) || e.is(std::errc::not_a_directory)) - printInfo("cannot read potential root '%1%'", path); + printInfo("cannot read potential root %1%", PathFmt(path)); else throw; } @@ -289,8 +296,8 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R void LocalStore::findRootsNoTemp(Roots & roots, bool censor) { /* Process direct roots in {gcroots,profiles}. */ - findRoots((config->stateDir.get() / gcRootsDir).string(), std::filesystem::file_type::unknown, roots); - findRoots((config->stateDir.get() / "profiles").string(), std::filesystem::file_type::unknown, roots); + findRoots(config->stateDir.get() / gcRootsDir, std::filesystem::file_type::unknown, roots); + findRoots(config->stateDir.get() / "profiles", std::filesystem::file_type::unknown, roots); /* Add additional roots returned by different platforms-specific heuristics. This is typically used to add running programs to @@ -559,7 +566,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) results.paths.insert(path); uint64_t bytesFreed; - deleteStorePath(realPath.string(), bytesFreed, isKnownPath); + deleteStorePath(realPath, bytesFreed, isKnownPath); results.bytesFreed += bytesFreed; @@ -770,7 +777,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) std::string name = dirent->d_name; if (name == "." || name == "..") continue; - Path path = (linksDir / name).string(); + auto path = linksDir / name; auto st = lstat(path); @@ -780,10 +787,13 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) continue; } - printMsg(lvlTalkative, "deleting unused link '%1%'", path); + printMsg(lvlTalkative, "deleting unused link %1%", PathFmt(path)); - if (unlink(path.c_str()) == -1) - throw SysError("deleting '%1%'", path); + try { + std::filesystem::remove(path); + } catch (std::filesystem::filesystem_error & e) { + throw SystemError(e.code(), "deleting %s", PathFmt(path)); + } /* Do not account for deleted file here. Rely on deletePath() accounting. */ diff --git a/src/libstore/include/nix/store/binary-cache-store.hh b/src/libstore/include/nix/store/binary-cache-store.hh index a41bf515dc6..07184ec81c8 100644 --- a/src/libstore/include/nix/store/binary-cache-store.hh +++ b/src/libstore/include/nix/store/binary-cache-store.hh @@ -39,7 +39,8 @@ struct BinaryCacheStoreConfig : virtual StoreConfig fetch debug info on demand )"}; - Setting secretKeyFile{this, "", "secret-key", "Path to the secret key used to sign the binary cache."}; + Setting secretKeyFile{ + this, "", "secret-key", "Path to the secret key used to sign the binary cache."}; Setting secretKeyFiles{ this, "", "secret-keys", "List of comma-separated paths to the secret keys used to sign the binary cache."}; diff --git a/src/libstore/include/nix/store/builtins/buildenv.hh b/src/libstore/include/nix/store/builtins/buildenv.hh index 136a1ab5a77..a0f0b3f24b9 100644 --- a/src/libstore/include/nix/store/builtins/buildenv.hh +++ b/src/libstore/include/nix/store/builtins/buildenv.hh @@ -2,6 +2,7 @@ ///@file #include "nix/store/store-api.hh" +#include "nix/util/fmt.hh" namespace nix { @@ -10,11 +11,11 @@ namespace nix { */ struct Package { - Path path; + std::filesystem::path path; bool active; int priority; - Package(const Path & path, bool active, int priority) + Package(const std::filesystem::path & path, bool active, int priority) : path{path} , active{active} , priority{priority} @@ -25,18 +26,18 @@ struct Package class BuildEnvFileConflictError final : public CloneableError { public: - const Path fileA; - const Path fileB; + const std::filesystem::path fileA; + const std::filesystem::path fileB; int priority; - BuildEnvFileConflictError(const Path fileA, const Path fileB, int priority) + BuildEnvFileConflictError(const std::filesystem::path fileA, const std::filesystem::path fileB, int priority) : CloneableError( "Unable to build profile. There is a conflict for the following files:\n" "\n" " %1%\n" " %2%", - fileA, - fileB) + PathFmt(fileA), + PathFmt(fileB)) , fileA(fileA) , fileB(fileB) , priority(priority) @@ -46,6 +47,6 @@ public: typedef std::vector Packages; -void buildProfile(const Path & out, Packages && pkgs); +void buildProfile(const std::filesystem::path & out, Packages && pkgs); } // namespace nix diff --git a/src/libstore/include/nix/store/common-ssh-store-config.hh b/src/libstore/include/nix/store/common-ssh-store-config.hh index 0f2cea5e5fb..7f8fc97b185 100644 --- a/src/libstore/include/nix/store/common-ssh-store-config.hh +++ b/src/libstore/include/nix/store/common-ssh-store-config.hh @@ -15,7 +15,7 @@ struct CommonSSHStoreConfig : virtual StoreConfig CommonSSHStoreConfig(std::string_view scheme, const ParsedURL::Authority & authority, const Params & params); CommonSSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params); - Setting sshKey{ + Setting sshKey{ this, "", "ssh-key", "Path to the SSH private key used to authenticate to the remote machine."}; Setting sshPublicHostKey{ diff --git a/src/libstore/include/nix/store/indirect-root-store.hh b/src/libstore/include/nix/store/indirect-root-store.hh index c39e8ea69f7..d477a320aa7 100644 --- a/src/libstore/include/nix/store/indirect-root-store.hh +++ b/src/libstore/include/nix/store/indirect-root-store.hh @@ -55,7 +55,7 @@ struct IndirectRootStore : public virtual LocalFSStore * The implementation of this method is concrete, but it delegates * to `addIndirectRoot()` which is abstract. */ - Path addPermRoot(const StorePath & storePath, const Path & gcRoot) override final; + std::filesystem::path addPermRoot(const StorePath & storePath, const std::filesystem::path & gcRoot) override final; /** * Add an indirect root, which is a weak reference to the @@ -66,10 +66,10 @@ struct IndirectRootStore : public virtual LocalFSStore * * The form this weak-reference takes is implementation-specific. */ - virtual void addIndirectRoot(const Path & path) = 0; + virtual void addIndirectRoot(const std::filesystem::path & path) = 0; protected: - void makeSymlink(const Path & link, const Path & target); + void makeSymlink(const std::filesystem::path & link, const std::filesystem::path & target); }; } // namespace nix diff --git a/src/libstore/include/nix/store/local-binary-cache-store.hh b/src/libstore/include/nix/store/local-binary-cache-store.hh index 2846a9225c7..2438b37155c 100644 --- a/src/libstore/include/nix/store/local-binary-cache-store.hh +++ b/src/libstore/include/nix/store/local-binary-cache-store.hh @@ -14,7 +14,7 @@ struct LocalBinaryCacheStoreConfig : std::enable_shared_from_this> - makeRootDirSetting(LocalFSStoreConfig & self, std::optional defaultValue) + makeRootDirSetting(LocalFSStoreConfig & self, std::optional defaultValue) { return { &self, @@ -41,33 +41,33 @@ private: * An indirection so that we don't need to refer to global settings * in headers. */ - static Path getDefaultStateDir(); + static std::filesystem::path getDefaultStateDir(); /** * An indirection so that we don't need to refer to global settings * in headers. */ - static Path getDefaultLogDir(); + static std::filesystem::path getDefaultLogDir(); public: Setting stateDir{ this, - rootDir.get() ? *rootDir.get() / "nix/var/nix" : std::filesystem::path(getDefaultStateDir()), + rootDir.get() ? *rootDir.get() / "nix" / "var" / "nix" : getDefaultStateDir(), "state", "Directory where Nix stores state.", }; Setting logDir{ this, - rootDir.get() ? *rootDir.get() / "nix/var/log/nix" : std::filesystem::path(getDefaultLogDir()), + rootDir.get() ? *rootDir.get() / "nix" / "var" / "log" / "nix" : getDefaultLogDir(), "log", "directory where Nix stores log files.", }; Setting realStoreDir{ this, - rootDir.get() ? *rootDir.get() / "nix/store" : std::filesystem::path(storeDir), + rootDir.get() ? *rootDir.get() / "nix" / "store" : std::filesystem::path{storeDir}, "real", "Physical path of the Nix store.", }; @@ -105,16 +105,16 @@ struct alignas(8) /* Work around ASAN failures on i686-linux. */ * How the permanent GC root corresponding to this symlink is * managed is implementation-specific. */ - virtual Path addPermRoot(const StorePath & storePath, const Path & gcRoot) = 0; + virtual std::filesystem::path addPermRoot(const StorePath & storePath, const std::filesystem::path & gcRoot) = 0; virtual std::filesystem::path getRealStoreDir() { return config.realStoreDir; } - Path toRealPath(const StorePath & storePath) + std::filesystem::path toRealPath(const StorePath & storePath) { - return (getRealStoreDir() / storePath.to_string()).string(); + return getRealStoreDir() / storePath.to_string(); } std::optional getBuildLogExact(const StorePath & path) override; diff --git a/src/libstore/include/nix/store/local-overlay-store.hh b/src/libstore/include/nix/store/local-overlay-store.hh index 23bea471ad4..3c035007396 100644 --- a/src/libstore/include/nix/store/local-overlay-store.hh +++ b/src/libstore/include/nix/store/local-overlay-store.hh @@ -99,7 +99,7 @@ protected: * at that file path. It might be stored in the lower layer instead, * or it might not be part of this store at all. */ - Path toUpperPath(const StorePath & path) const; + std::filesystem::path toUpperPath(const StorePath & path) const; friend struct LocalOverlayStore; }; @@ -184,7 +184,7 @@ private: * Check which layers the store object exists in to try to avoid * needing to remount. */ - void deleteStorePath(const Path & path, uint64_t & bytesFreed, bool isKnownPath) override; + void deleteStorePath(const std::filesystem::path & path, uint64_t & bytesFreed, bool isKnownPath) override; /** * Deduplicate by removing store objects from the upper layer that diff --git a/src/libstore/include/nix/store/local-store.hh b/src/libstore/include/nix/store/local-store.hh index c30ddaadd17..eb4d971a18a 100644 --- a/src/libstore/include/nix/store/local-store.hh +++ b/src/libstore/include/nix/store/local-store.hh @@ -244,7 +244,7 @@ public: /** * Hack for build-remote.cc. */ - PathSet locksHeld; + PathSetNG locksHeld; /** * Initialise the local store, upgrading the schema if @@ -319,7 +319,7 @@ public: * The weak reference merely is a symlink to `path' from * /nix/var/nix/gcroots/auto/. */ - void addIndirectRoot(const Path & path) override; + void addIndirectRoot(const std::filesystem::path & path) override; private: @@ -353,7 +353,7 @@ public: * @param isKnownPath true if this is a known store path, false if it's * garbage/unknown content found in the store directory */ - virtual void deleteStorePath(const Path & path, uint64_t & bytesFreed, bool isKnownPath); + virtual void deleteStorePath(const std::filesystem::path & path, uint64_t & bytesFreed, bool isKnownPath); /** * Optimise the disk space usage of the Nix store by hard-linking @@ -367,7 +367,7 @@ public: * Optimise a single store path. Optionally, test the encountered * symlinks for corruption. */ - void optimisePath(const Path & path, RepairFlag repair); + void optimisePath(const std::filesystem::path & path, RepairFlag repair); bool verifyStore(bool checkContents, RepairFlag repair) override; @@ -481,7 +481,7 @@ private: PathSet queryValidPathsOld(); ValidPathInfo queryPathInfoOld(const Path & path); - void findRoots(const Path & path, std::filesystem::file_type type, Roots & roots); + void findRoots(const std::filesystem::path & path, std::filesystem::file_type type, Roots & roots); void findRootsNoTemp(Roots & roots, bool censor); diff --git a/src/libstore/include/nix/store/machines.hh b/src/libstore/include/nix/store/machines.hh index 051ec1454fc..6b348469949 100644 --- a/src/libstore/include/nix/store/machines.hh +++ b/src/libstore/include/nix/store/machines.hh @@ -17,7 +17,7 @@ struct Machine const StoreReference storeUri; const StringSet systemTypes; - const std::string sshKey; + const std::filesystem::path sshKey; const unsigned int maxJobs; const float speedFactor; const StringSet supportedFeatures; diff --git a/src/libstore/include/nix/store/nar-info-disk-cache.hh b/src/libstore/include/nix/store/nar-info-disk-cache.hh index 194f45f9cf7..c8a3567c27d 100644 --- a/src/libstore/include/nix/store/nar-info-disk-cache.hh +++ b/src/libstore/include/nix/store/nar-info-disk-cache.hh @@ -59,7 +59,7 @@ struct NarInfoDiskCache */ static ref get(const Settings & settings, SQLiteSettings); - static ref getTest(const Settings & settings, SQLiteSettings, Path dbPath); + static ref getTest(const Settings & settings, SQLiteSettings, std::filesystem::path dbPath); }; } // namespace nix diff --git a/src/libstore/include/nix/store/posix-fs-canonicalise.hh b/src/libstore/include/nix/store/posix-fs-canonicalise.hh index 7767f05d869..8a8b0eca309 100644 --- a/src/libstore/include/nix/store/posix-fs-canonicalise.hh +++ b/src/libstore/include/nix/store/posix-fs-canonicalise.hh @@ -4,6 +4,8 @@ #include #include +#include + #include "nix/util/types.hh" #include "nix/util/error.hh" #include "nix/store/config.hh" @@ -60,11 +62,12 @@ struct CanonicalizePathMetadataOptions * - the owner and group are set to the Nix user and group, if we're * running as root. (Unix only.) */ -void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen); +void canonicalisePathMetaData( + const std::filesystem::path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen); -void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options); +void canonicalisePathMetaData(const std::filesystem::path & path, CanonicalizePathMetadataOptions options); -void canonicaliseTimestampAndPermissions(const Path & path); +void canonicaliseTimestampAndPermissions(const std::filesystem::path & path); MakeError(PathInUse, Error); diff --git a/src/libstore/include/nix/store/ssh.hh b/src/libstore/include/nix/store/ssh.hh index 574cb5cf414..c64e9b1cca9 100644 --- a/src/libstore/include/nix/store/ssh.hh +++ b/src/libstore/include/nix/store/ssh.hh @@ -9,7 +9,7 @@ namespace nix { -Strings getNixSshOpts(); +OsStrings getNixSshOpts(); class SSHMaster { @@ -18,7 +18,7 @@ private: ParsedURL::Authority authority; std::string hostnameAndUser; bool fakeSSH; - const std::string keyFile; + const std::filesystem::path keyFile; /** * Raw bytes, not Base64 encoding. */ @@ -34,23 +34,23 @@ private: #ifndef _WIN32 // TODO re-enable on Windows, once we can start processes. Pid sshMaster; #endif - Path socketPath; + std::filesystem::path socketPath; }; Sync state_; - void addCommonSSHOpts(Strings & args); + void addCommonSSHOpts(OsStrings & args); bool isMasterRunning(); #ifndef _WIN32 // TODO re-enable on Windows, once we can start processes. - Path startMaster(); + std::filesystem::path startMaster(); #endif public: SSHMaster( const ParsedURL::Authority & authority, - std::string_view keyFile, + std::filesystem::path keyFile, std::string_view sshPublicHostKey, bool useMaster, bool compress, @@ -83,7 +83,7 @@ public: * execute). Will not be used when "fake SSHing" to the local * machine. */ - std::unique_ptr startCommand(Strings && command, Strings && extraSshArgs = {}); + std::unique_ptr startCommand(OsStrings && command, OsStrings && extraSshArgs = {}); }; } // namespace nix diff --git a/src/libstore/include/nix/store/uds-remote-store.hh b/src/libstore/include/nix/store/uds-remote-store.hh index 764e8768a32..3b8dfadd10c 100644 --- a/src/libstore/include/nix/store/uds-remote-store.hh +++ b/src/libstore/include/nix/store/uds-remote-store.hh @@ -36,7 +36,7 @@ struct UDSRemoteStoreConfig : std::enable_shared_from_this * The default is `settings.nixDaemonSocketFile`, but we don't write * that below, instead putting in the constructor. */ - Path path; + std::filesystem::path path; static StringSet uriSchemes() { @@ -79,7 +79,7 @@ struct UDSRemoteStore : virtual IndirectRootStore, virtual RemoteStore * owned managed by the client's user account, and the server makes * the indirect symlink. */ - void addIndirectRoot(const Path & path) override; + void addIndirectRoot(const std::filesystem::path & path) override; private: diff --git a/src/libstore/indirect-root-store.cc b/src/libstore/indirect-root-store.cc index ae56ea311d8..7384456e286 100644 --- a/src/libstore/indirect-root-store.cc +++ b/src/libstore/indirect-root-store.cc @@ -2,28 +2,28 @@ namespace nix { -void IndirectRootStore::makeSymlink(const Path & link, const Path & target) +void IndirectRootStore::makeSymlink(const std::filesystem::path & link, const std::filesystem::path & target) { /* Create directories up to `gcRoot'. */ - createDirs(std::filesystem::path(link).parent_path()); + createDirs(link.parent_path()); /* Create the new symlink. */ - Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), rand()); + auto tempLink = std::filesystem::path(link) += fmt(".tmp-%1%-%2%", getpid(), rand()); createSymlink(target, tempLink); /* Atomically replace the old one. */ std::filesystem::rename(tempLink, link); } -Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot) +std::filesystem::path IndirectRootStore::addPermRoot(const StorePath & storePath, const std::filesystem::path & _gcRoot) { - Path gcRoot(canonPath(_gcRoot).string()); + auto gcRoot = canonPath(_gcRoot); - if (isInStore(gcRoot)) + if (isInStore(gcRoot.string())) throw Error( "creating a garbage collector root (%1%) in the Nix store is forbidden " "(are you running nix-build inside the store?)", - gcRoot); + PathFmt(gcRoot)); /* Register this root with the garbage collector, if it's running. This should be superfluous since the caller should @@ -34,7 +34,7 @@ Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _g /* Don't clobber the link if it already exists and doesn't point to the Nix store. */ if (pathExists(gcRoot) && (!std::filesystem::is_symlink(gcRoot) || !isInStore(readLink(gcRoot).string()))) - throw Error("cannot create symlink '%1%'; already exists", gcRoot); + throw Error("cannot create symlink %1%; already exists", PathFmt(gcRoot)); makeSymlink(gcRoot, printStorePath(storePath)); addIndirectRoot(gcRoot); diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc index 7c58c7226eb..b2f2cf8b243 100644 --- a/src/libstore/legacy-ssh-store.cc +++ b/src/libstore/legacy-ssh-store.cc @@ -62,7 +62,7 @@ ref LegacySSHStore::openConnection() command.push_back("--store"); command.push_back(config->remoteStore.get()); } - conn->sshConn = master.startCommand(std::move(command), std::list{config->extraSshArgs}); + conn->sshConn = master.startCommand(toOsStrings(std::move(command)), toOsStrings(std::list{config->extraSshArgs})); if (config->connPipeSize) { conn->sshConn->trySetBufferSize(*config->connPipeSize); } diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc index 19c1f2794f4..ce4f2358d52 100644 --- a/src/libstore/local-binary-cache-store.cc +++ b/src/libstore/local-binary-cache-store.cc @@ -29,7 +29,7 @@ StoreReference LocalBinaryCacheStoreConfig::getReference() const .variant = StoreReference::Specified{ .scheme = "file", - .authority = binaryCacheDir, + .authority = binaryCacheDir.string(), }, }; } @@ -56,7 +56,8 @@ struct LocalBinaryCacheStore : virtual BinaryCacheStore void upsertFile( const std::string & path, RestartableSource & source, const std::string & mimeType, uint64_t sizeHint) override { - auto path2 = std::filesystem::path{config->binaryCacheDir} / path; + assert(!std::filesystem::path(path).is_absolute()); + auto path2 = config->binaryCacheDir / path; static std::atomic counter{0}; createDirs(path2.parent_path()); auto tmp = path2; @@ -69,8 +70,9 @@ struct LocalBinaryCacheStore : virtual BinaryCacheStore void getFile(const std::string & path, Sink & sink) override { + assert(!std::filesystem::path(path).is_absolute()); try { - readFile(config->binaryCacheDir + "/" + path, sink); + readFile(config->binaryCacheDir / path, sink); } catch (SystemError & e) { if (e.is(std::errc::no_such_file_or_directory)) throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache", path); @@ -101,17 +103,18 @@ struct LocalBinaryCacheStore : virtual BinaryCacheStore void LocalBinaryCacheStore::init() { - createDirs(config->binaryCacheDir + "/nar"); - createDirs(config->binaryCacheDir + "/" + realisationsPrefix); + createDirs(config->binaryCacheDir / "nar"); + createDirs(config->binaryCacheDir / realisationsPrefix); if (config->writeDebugInfo) - createDirs(config->binaryCacheDir + "/debuginfo"); - createDirs(config->binaryCacheDir + "/log"); + createDirs(config->binaryCacheDir / "debuginfo"); + createDirs(config->binaryCacheDir / "log"); BinaryCacheStore::init(); } bool LocalBinaryCacheStore::fileExists(const std::string & path) { - return pathExists(config->binaryCacheDir + "/" + path); + assert(!std::filesystem::path(path).is_absolute()); + return pathExists(config->binaryCacheDir / path); } StringSet LocalBinaryCacheStoreConfig::uriSchemes() diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc index e37dbc0d8c0..89925098f16 100644 --- a/src/libstore/local-fs-store.cc +++ b/src/libstore/local-fs-store.cc @@ -8,14 +8,14 @@ namespace nix { -Path LocalFSStoreConfig::getDefaultStateDir() +std::filesystem::path LocalFSStoreConfig::getDefaultStateDir() { - return settings.nixStateDir.string(); + return settings.nixStateDir; } -Path LocalFSStoreConfig::getDefaultLogDir() +std::filesystem::path LocalFSStoreConfig::getDefaultLogDir() { - return settings.getLogFileSettings().nixLogDir.string(); + return settings.getLogFileSettings().nixLogDir; } LocalFSStoreConfig::LocalFSStoreConfig(PathView rootDir, const Params & params) @@ -29,9 +29,7 @@ LocalFSStoreConfig::LocalFSStoreConfig(PathView rootDir, const Params & params) * manually repeat the same normalization logic. */ , rootDir{makeRootDirSetting( - *this, - !rootDir.empty() && params.count("root") == 0 ? std::optional{canonPath(rootDir).string()} - : std::nullopt)} + *this, !rootDir.empty() && params.count("root") == 0 ? std::optional{canonPath(rootDir)} : std::nullopt)} { } diff --git a/src/libstore/local-overlay-store.cc b/src/libstore/local-overlay-store.cc index 6242f9e006c..705e9ddf71d 100644 --- a/src/libstore/local-overlay-store.cc +++ b/src/libstore/local-overlay-store.cc @@ -34,9 +34,9 @@ StoreReference LocalOverlayStoreConfig::getReference() const }; } -Path LocalOverlayStoreConfig::toUpperPath(const StorePath & path) const +std::filesystem::path LocalOverlayStoreConfig::toUpperPath(const StorePath & path) const { - return (upperLayer.get() / path.to_string()).string(); + return upperLayer.get() / path.to_string(); } LocalOverlayStore::LocalOverlayStore(ref config) @@ -205,19 +205,18 @@ void LocalOverlayStore::collectGarbage(const GCOptions & options, GCResults & re remountIfNecessary(); } -void LocalOverlayStore::deleteStorePath(const Path & path, uint64_t & bytesFreed, bool isKnownPath) +void LocalOverlayStore::deleteStorePath(const std::filesystem::path & path, uint64_t & bytesFreed, bool isKnownPath) { - auto mergedDir = config->realStoreDir.get().string() + "/"; - if (path.substr(0, mergedDir.length()) != mergedDir) { - warn("local-overlay: unexpected gc path '%s' ", path); + if (path.parent_path() != config->realStoreDir.get()) { + warn("local-overlay: unexpected gc path %s", PathFmt(path)); return; } - StorePath storePath = {path.substr(mergedDir.length())}; + StorePath storePath = {path.filename().string()}; auto upperPath = config->toUpperPath(storePath); if (pathExists(upperPath)) { - debug("upper exists: %s", path); + debug("upper exists: %s", PathFmt(path)); if (lowerStore->isValidPath(storePath)) { debug("lower exists: %s", storePath.to_string()); // Path also exists in lower store. diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index ada70f3b63e..a637a111c2a 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -235,7 +235,7 @@ LocalStore::LocalStore(ref config) if (!config->readOnly) { auto globalLockPath = dbDir / "big-lock"; try { - globalLock = openLockFile(globalLockPath.c_str(), true); + globalLock = openLockFile(globalLockPath, true); } catch (SystemError & e) { if (e.is(std::errc::permission_denied) || e.is(std::errc::operation_not_permitted)) { e.addTrace( @@ -409,7 +409,7 @@ AutoCloseFD LocalStore::openGCLock() return toDescriptor(fdGCLock); } -void LocalStore::deleteStorePath(const Path & path, uint64_t & bytesFreed, bool isKnownPath) +void LocalStore::deleteStorePath(const std::filesystem::path & path, uint64_t & bytesFreed, bool isKnownPath) { try { deletePath(path, bytesFreed); @@ -417,15 +417,15 @@ void LocalStore::deleteStorePath(const Path & path, uint64_t & bytesFreed, bool if (config->ignoreGcDeleteFailure) { logWarning( {.msg = HintFmt( - isKnownPath ? "ignoring failure to remove store path '%1%': %2%" - : "ignoring failure to remove garbage in store directory '%1%': %2%", - path, + isKnownPath ? "ignoring failure to remove store path %1%: %2%" + : "ignoring failure to remove garbage in store directory %1%: %2%", + PathFmt(path), e.info().msg)}); } else { e.addTrace( {}, - isKnownPath ? "While deleting store path '%1%'" : "While deleting garbage in store directory '%1%'", - path); + isKnownPath ? "While deleting store path %1%" : "While deleting garbage in store directory %1%", + PathFmt(path)); throw; } } @@ -450,7 +450,9 @@ LocalStore::~LocalStore() auto fdTempRoots(_fdTempRoots.lock()); if (*fdTempRoots) { fdTempRoots->close(); - unlink(fnTempRoots.string().c_str()); + /* The error code of std::filesystem::remove() is intentionally ignored. */ + std::error_code ec; + std::filesystem::remove(fnTempRoots, ec); } } catch (...) { ignoreExceptionInDestructor(); diff --git a/src/libstore/machines.cc b/src/libstore/machines.cc index 1a97f96a250..3b11ec90252 100644 --- a/src/libstore/machines.cc +++ b/src/libstore/machines.cc @@ -69,8 +69,8 @@ StoreReference Machine::completeStoreReference() const } if (generic && (generic->scheme == "ssh" || generic->scheme == "ssh-ng")) { - if (sshKey != "") - storeUri.params["ssh-key"] = sshKey; + if (!sshKey.empty()) + storeUri.params["ssh-key"] = sshKey.string(); if (sshPublicHostKey != "") storeUri.params["base64-ssh-public-host-key"] = sshPublicHostKey; } diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc index 640a7e402db..b5c92b63736 100644 --- a/src/libstore/nar-info-disk-cache.cc +++ b/src/libstore/nar-info-disk-cache.cc @@ -377,7 +377,8 @@ ref NarInfoDiskCache::get(const Settings & settings, SQLiteSet return cache; } -ref NarInfoDiskCache::getTest(const Settings & settings, SQLiteSettings sqliteSettings, Path dbPath) +ref +NarInfoDiskCache::getTest(const Settings & settings, SQLiteSettings sqliteSettings, std::filesystem::path dbPath) { return make_ref(settings, sqliteSettings, dbPath); } diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 79736cd47b8..7d37dbf9d4a 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -320,7 +320,7 @@ void LocalStore::optimiseStore() printInfo("%s freed by hard-linking %d files", renderSize(stats.bytesFreed), stats.filesLinked); } -void LocalStore::optimisePath(const Path & path, RepairFlag repair) +void LocalStore::optimisePath(const std::filesystem::path & path, RepairFlag repair) { OptimiseStats stats; InodeHash inodeHash; diff --git a/src/libstore/posix-fs-canonicalise.cc b/src/libstore/posix-fs-canonicalise.cc index 7af63755e5d..455cc7c4f5d 100644 --- a/src/libstore/posix-fs-canonicalise.cc +++ b/src/libstore/posix-fs-canonicalise.cc @@ -15,7 +15,7 @@ namespace nix { const time_t mtimeStore = 1; /* 1 second into the epoch */ -static void canonicaliseTimestampAndPermissions(const Path & path, const PosixStat & st) +static void canonicaliseTimestampAndPermissions(const std::filesystem::path & path, const PosixStat & st) { if (!S_ISLNK(st.st_mode)) { @@ -36,13 +36,13 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const PosixSt #endif } -void canonicaliseTimestampAndPermissions(const Path & path) +void canonicaliseTimestampAndPermissions(const std::filesystem::path & path) { canonicaliseTimestampAndPermissions(path, lstat(path)); } -static void -canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen) +static void canonicalisePathMetaData_( + const std::filesystem::path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen) { checkInterrupt(); @@ -52,7 +52,7 @@ canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions opt setattrlist() to remove other attributes as well. */ if (lchflags(path.c_str(), 0)) { if (errno != ENOTSUP) - throw SysError("clearing flags of path '%1%'", path); + throw SysError("clearing flags of path %1%", PathFmt(path)); } #endif @@ -60,7 +60,7 @@ canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions opt /* Really make sure that the path is of a supported type. */ if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))) - throw Error("file '%1%' has an unsupported type", path); + throw Error("file %1% has an unsupported type", PathFmt(path)); #if NIX_SUPPORT_ACL /* Remove extended attributes / ACLs. */ @@ -68,18 +68,18 @@ canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions opt if (eaSize < 0) { if (errno != ENOTSUP && errno != ENODATA) - throw SysError("querying extended attributes of '%s'", path); + throw SysError("querying extended attributes of %s", PathFmt(path)); } else if (eaSize > 0) { std::vector eaBuf(eaSize); if ((eaSize = llistxattr(path.c_str(), eaBuf.data(), eaBuf.size())) < 0) - throw SysError("querying extended attributes of '%s'", path); + throw SysError("querying extended attributes of %s", PathFmt(path)); for (auto & eaName : tokenizeString(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) { if (options.ignoredAcls.count(eaName)) continue; if (lremovexattr(path.c_str(), eaName.c_str()) == -1) - throw SysError("removing extended attribute '%s' from '%s'", eaName, path); + throw SysError("removing extended attribute '%s' from %s", eaName, PathFmt(path)); } } #endif @@ -93,7 +93,7 @@ canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions opt (i.e. "touch $out/foo; ln $out/foo $out/bar"). */ if (options.uidRange && (st.st_uid < options.uidRange->first || st.st_uid > options.uidRange->second)) { if (S_ISDIR(st.st_mode) || !inodesSeen.count(Inode(st.st_dev, st.st_ino))) - throw BuildError(BuildResult::Failure::OutputRejected, "invalid ownership on file '%1%'", path); + throw BuildError(BuildResult::Failure::OutputRejected, "invalid ownership on file %1%", PathFmt(path)); mode_t mode = st.st_mode & ~S_IFMT; assert( S_ISLNK(st.st_mode) @@ -110,24 +110,25 @@ canonicalisePathMetaData_(const Path & path, CanonicalizePathMetadataOptions opt /* Change ownership to the current uid. */ if (st.st_uid != geteuid()) { if (lchown(path.c_str(), geteuid(), getegid()) == -1) - throw SysError("changing owner of '%1%' to %2%", path, geteuid()); + throw SysError("changing owner of %1% to %2%", PathFmt(path), geteuid()); } #endif if (S_ISDIR(st.st_mode)) { for (auto & i : DirectoryIterator{path}) { checkInterrupt(); - canonicalisePathMetaData_(i.path().string(), options, inodesSeen); + canonicalisePathMetaData_(i.path(), options, inodesSeen); } } } -void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen) +void canonicalisePathMetaData( + const std::filesystem::path & path, CanonicalizePathMetadataOptions options, InodesSeen & inodesSeen) { canonicalisePathMetaData_(path, options, inodesSeen); } -void canonicalisePathMetaData(const Path & path, CanonicalizePathMetadataOptions options) +void canonicalisePathMetaData(const std::filesystem::path & path, CanonicalizePathMetadataOptions options) { InodesSeen inodesSeen; canonicalisePathMetaData_(path, options, inodesSeen); diff --git a/src/libstore/restricted-store.cc b/src/libstore/restricted-store.cc index a0e9d4504f6..5248a313c24 100644 --- a/src/libstore/restricted-store.cc +++ b/src/libstore/restricted-store.cc @@ -125,7 +125,7 @@ struct RestrictedStore : public virtual IndirectRootStore, public virtual GcStor void addTempRoot(const StorePath & path) override {} - void addIndirectRoot(const Path & path) override {} + void addIndirectRoot(const std::filesystem::path & path) override {} Roots findRoots(bool censor) override { diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc index dc70b4ba8de..aab9741640c 100644 --- a/src/libstore/ssh-store.cc +++ b/src/libstore/ssh-store.cc @@ -177,12 +177,12 @@ struct MountedSSHStore : virtual SSHStore, virtual LocalFSStore * privilege escalation / symlinks in directories owned by the * originating requester that they cannot delete. */ - Path addPermRoot(const StorePath & path, const Path & gcRoot) override + std::filesystem::path addPermRoot(const StorePath & path, const std::filesystem::path & gcRoot) override { auto conn(getConnection()); conn->to << WorkerProto::Op::AddPermRoot; WorkerProto::write(*this, *conn, path); - WorkerProto::write(*this, *conn, gcRoot); + WorkerProto::write(*this, *conn, gcRoot.string()); conn.processStderr(); return readString(conn->from); } @@ -208,7 +208,7 @@ ref SSHStore::openConnection() command.push_back(config->remoteStore.get()); } command.insert(command.end(), extraRemoteProgramArgs.begin(), extraRemoteProgramArgs.end()); - conn->sshConn = master.startCommand(std::move(command)); + conn->sshConn = master.startCommand(toOsStrings(std::move(command))); conn->to = FdSink(conn->sshConn->in.get()); conn->from = FdSource(conn->sshConn->out.get()); return conn; diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index 2b567af1317..849fcff2fdf 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -52,12 +52,12 @@ static void checkValidAuthority(const ParsedURL::Authority & authority) } } -Strings getNixSshOpts() +OsStrings getNixSshOpts() { std::string sshOpts = getEnv("NIX_SSHOPTS").value_or(""); try { - return shellSplitString(sshOpts); + return toOsStrings(shellSplitString(sshOpts)); } catch (Error & e) { e.addTrace({}, "while splitting NIX_SSHOPTS '%s'", sshOpts); throw; @@ -66,7 +66,7 @@ Strings getNixSshOpts() SSHMaster::SSHMaster( const ParsedURL::Authority & authority, - std::string_view keyFile, + std::filesystem::path keyFile, std::string_view sshPublicHostKey, bool useMaster, bool compress, @@ -80,7 +80,7 @@ SSHMaster::SSHMaster( return std::move(oss).str(); }()) , fakeSSH(authority.to_string() == "localhost") - , keyFile(keyFile) + , keyFile(std::move(keyFile)) , sshPublicHostKey(parsePublicHostKey(authority.host, sshPublicHostKey)) , useMaster(useMaster && !fakeSSH) , compress(compress) @@ -90,39 +90,38 @@ SSHMaster::SSHMaster( checkValidAuthority(authority); } -void SSHMaster::addCommonSSHOpts(Strings & args) +void SSHMaster::addCommonSSHOpts(OsStrings & args) { auto sshArgs = getNixSshOpts(); args.insert(args.end(), sshArgs.begin(), sshArgs.end()); if (!keyFile.empty()) - args.insert(args.end(), {"-i", keyFile}); + args.insert(args.end(), {OS_STR("-i"), keyFile.native()}); if (!sshPublicHostKey.empty()) { std::filesystem::path fileName = tmpDir->path() / "host-key"; writeFile(fileName, authority.host + " " + sshPublicHostKey + "\n"); - args.insert(args.end(), {"-oUserKnownHostsFile=" + fileName.string()}); + args.insert(args.end(), {OS_STR("-oUserKnownHostsFile=") + fileName.native()}); } if (compress) - args.push_back("-C"); + args.push_back(OS_STR("-C")); if (authority.port) - args.push_back(fmt("-p%d", *authority.port)); + args.push_back(string_to_os_string(fmt("-p%d", *authority.port))); // We use this to make ssh signal back to us that the connection is established. // It really does run locally; see createSSHEnv which sets up SHELL to make // it launch more reliably. The local command runs synchronously, so presumably // the remote session won't be garbled if the local command is slow. - args.push_back("-oPermitLocalCommand=yes"); - args.push_back("-oLocalCommand=echo started"); + args.push_back(OS_STR("-oPermitLocalCommand=yes")); + args.push_back(OS_STR("-oLocalCommand=echo started")); } bool SSHMaster::isMasterRunning() { - Strings args = {"-O", "check", hostnameAndUser}; + OsStrings args = {OS_STR("-O"), OS_STR("check"), string_to_os_string(hostnameAndUser)}; addCommonSSHOpts(args); - auto res = - runProgram(RunOptions{.program = "ssh", .args = toOsStrings(std::move(args)), .mergeStderrToStdout = true}); + auto res = runProgram(RunOptions{.program = "ssh", .args = std::move(args), .mergeStderrToStdout = true}); return res.first == 0; } @@ -147,12 +146,12 @@ Strings createSSHEnv() return r; } -std::unique_ptr SSHMaster::startCommand(Strings && command, Strings && extraSshArgs) +std::unique_ptr SSHMaster::startCommand(OsStrings && command, OsStrings && extraSshArgs) { #ifdef _WIN32 // TODO re-enable on Windows, once we can start processes. throw UnimplementedError("cannot yet SSH on windows because spawning processes is not yet implemented"); #else - Path socketPath = startMaster(); + std::filesystem::path socketPath = startMaster(); Pipe in, out; in.create(); @@ -181,13 +180,13 @@ std::unique_ptr SSHMaster::startCommand(Strings && comman if (logFD != -1 && dup2(logFD, STDERR_FILENO) == -1) throw SysError("duping over stderr"); - Strings args; + OsStrings args; if (!fakeSSH) { args = {"ssh", hostnameAndUser.c_str(), "-x"}; addCommonSSHOpts(args); - if (socketPath != "") - args.insert(args.end(), {"-S", socketPath}); + if (!socketPath.empty()) + args.insert(args.end(), {"-S", socketPath.string()}); if (verbosity >= lvlChatty) args.push_back("-v"); args.splice(args.end(), std::move(extraSshArgs)); @@ -230,17 +229,17 @@ std::unique_ptr SSHMaster::startCommand(Strings && comman #ifndef _WIN32 // TODO re-enable on Windows, once we can start processes. -Path SSHMaster::startMaster() +std::filesystem::path SSHMaster::startMaster() { if (!useMaster) - return ""; + return {}; auto state(state_.lock()); if (state->sshMaster != INVALID_DESCRIPTOR) return state->socketPath; - state->socketPath = (Path) *tmpDir + "/ssh.sock"; + state->socketPath = tmpDir->path() / "ssh.sock"; Pipe out; out.create(); @@ -262,7 +261,7 @@ Path SSHMaster::startMaster() if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) throw SysError("duping over stdout"); - Strings args = {"ssh", hostnameAndUser.c_str(), "-M", "-N", "-S", state->socketPath}; + OsStrings args = {"ssh", hostnameAndUser.c_str(), "-M", "-N", "-S", state->socketPath.string()}; if (verbosity >= lvlChatty) args.push_back("-v"); addCommonSSHOpts(args); diff --git a/src/libstore/uds-remote-store.cc b/src/libstore/uds-remote-store.cc index 488a7cc3c0b..7c4595c634e 100644 --- a/src/libstore/uds-remote-store.cc +++ b/src/libstore/uds-remote-store.cc @@ -24,7 +24,7 @@ UDSRemoteStoreConfig::UDSRemoteStoreConfig( : Store::Config{params} , LocalFSStore::Config{params} , RemoteStore::Config{params} - , path{authority.empty() ? settings.nixDaemonSocketFile.string() : authority} + , path{authority.empty() ? settings.nixDaemonSocketFile : std::filesystem::path{authority}} { if (uriSchemes().count(scheme) == 0) { throw UsageError("Scheme must be 'unix'"); @@ -69,7 +69,7 @@ StoreReference UDSRemoteStoreConfig::getReference() const .variant = StoreReference::Specified{ .scheme = *uriSchemes().begin(), - .authority = path, + .authority = path.string(), }, .params = getQueryParams(), }; @@ -95,10 +95,10 @@ ref UDSRemoteStore::openConnection() return conn; } -void UDSRemoteStore::addIndirectRoot(const Path & path) +void UDSRemoteStore::addIndirectRoot(const std::filesystem::path & path) { auto conn(getConnection()); - conn->to << WorkerProto::Op::AddIndirectRoot << path; + conn->to << WorkerProto::Op::AddIndirectRoot << path.string(); conn.processStderr(); readInt(conn->from); } diff --git a/src/libstore/unix/build/chroot-derivation-builder.cc b/src/libstore/unix/build/chroot-derivation-builder.cc index c677383ef1e..d54aa4bbe25 100644 --- a/src/libstore/unix/build/chroot-derivation-builder.cc +++ b/src/libstore/unix/build/chroot-derivation-builder.cc @@ -58,7 +58,8 @@ struct ChrootDerivationBuilder : virtual DerivationBuilderImpl environment using bind-mounts. We put it in the Nix store so that the build outputs can be moved efficiently from the chroot to their final location. */ - std::filesystem::path chrootParentDir = store.toRealPath(drvPath) + ".chroot"; + auto chrootParentDir = store.toRealPath(drvPath); + chrootParentDir += ".chroot"; deletePath(chrootParentDir); /* Clean up the chroot directory automatically. */ diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index 4a0abe9019e..f6185fc6c5e 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -481,7 +481,7 @@ class DerivationBuilderImpl : public DerivationBuilder, public DerivationBuilder }; static void handleDiffHook( - const Path & diffHook, + const std::filesystem::path & diffHook, uid_t uid, uid_t gid, const std::filesystem::path & tryA, @@ -1487,7 +1487,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() continue; } - auto optSt = maybeLstat(actualPath.c_str()); + auto optSt = maybeLstat(actualPath); if (!optSt) throw BuildError( BuildResult::Failure::OutputRejected, @@ -1863,7 +1863,8 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() if (newInfo.narHash != oldInfo.narHash) { auto * diffHook = localSettings.getDiffHook(); if (diffHook || settings.keepFailed) { - auto dst = store.toRealPath(newInfo.path) + ".check"; + auto dst = store.toRealPath(newInfo.path); + dst += ".check"; deletePath(dst); movePath(actualPath, dst); @@ -1879,15 +1880,15 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs() } throw NotDeterministic( - "derivation '%s' may not be deterministic: output '%s' differs from '%s'", + "derivation '%s' may not be deterministic: output %s differs from %s", store.printStorePath(drvPath), - store.toRealPath(newInfo.path), - dst); + PathFmt(store.toRealPath(newInfo.path)), + PathFmt(dst)); } else throw NotDeterministic( - "derivation '%s' may not be deterministic: output '%s' differs", + "derivation '%s' may not be deterministic: output %s differs", store.printStorePath(drvPath), - store.toRealPath(newInfo.path)); + PathFmt(store.toRealPath(newInfo.path))); } /* Since we verified the build, it's now ultimately trusted. */ diff --git a/src/libstore/unix/pathlocks.cc b/src/libstore/unix/pathlocks.cc index 26410827cd0..50cb148cc0a 100644 --- a/src/libstore/unix/pathlocks.cc +++ b/src/libstore/unix/pathlocks.cc @@ -31,10 +31,12 @@ void deleteLockFile(const std::filesystem::path & path, Descriptor desc) races. Write a (meaningless) token to the file to indicate to other processes waiting on this lock that the lock is stale (deleted). */ - unlink(path.c_str()); + std::error_code ec; + std::filesystem::remove(path, ec); writeFull(desc, "d"); - /* Note that the result of unlink() is ignored; removing the lock - file is an optimisation, not a necessity. */ + /* Note that the error code of std::filesystem::remove() is + intentionally ignored; removing the lock file is an optimisation, + not a necessity. */ } bool lockFile(Descriptor desc, LockType lockType, bool wait) @@ -82,7 +84,8 @@ bool PathLocks::lockPaths(const std::set & paths, const s preventing deadlocks. */ for (auto & path : paths) { checkInterrupt(); - std::filesystem::path lockPath = path + ".lock"; + auto lockPath = path; + lockPath += ".lock"; debug("locking path %1%", PathFmt(path)); diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc index 23cfb7aba6e..c573a7e3f77 100644 --- a/src/libutil/file-system.cc +++ b/src/libutil/file-system.cc @@ -587,7 +587,8 @@ AutoCloseFD createAnonymousTempFile() if (!fd2) throw SysError("creating temporary file %s", PathFmt(path)); fd = std::move(fd2); - unlink(requireCString(path)); /* We only care about the file descriptor. */ + std::error_code ec; + std::filesystem::remove(path, ec); /* We only care about the file descriptor. */ #endif return fd; @@ -614,7 +615,7 @@ std::filesystem::path makeTempPath(const std::filesystem::path & root, const std // start the counter at a random value to minimize issues with preexisting temp paths static std::atomic counter(std::random_device{}()); assert(!std::filesystem::path(suffix).is_absolute()); - auto tmpRoot = canonPath(root.empty() ? defaultTempDir().string() : root.string(), true); + auto tmpRoot = canonPath(root.empty() ? defaultTempDir() : root, true); return tmpRoot / fmt("%s-%s-%s", suffix, getpid(), counter.fetch_add(1, std::memory_order_relaxed)); } diff --git a/src/nix/nix-build/nix-build.cc b/src/nix/nix-build/nix-build.cc index d09cb677aa1..acbf76fa743 100644 --- a/src/nix/nix-build/nix-build.cc +++ b/src/nix/nix-build/nix-build.cc @@ -735,7 +735,7 @@ static void main_nix_build(int argc, char ** argv) std::string symlink = drvPrefix; if (outputName != "out") symlink += "-" + outputName; - store2->addPermRoot(outputPath, absPath(symlink).string()); + store2->addPermRoot(outputPath, absPath(symlink)); } outPaths.push_back(outputPath); diff --git a/src/nix/nix-channel/nix-channel.cc b/src/nix/nix-channel/nix-channel.cc index 953ff7a7f6d..209f84d0a7e 100644 --- a/src/nix/nix-channel/nix-channel.cc +++ b/src/nix/nix-channel/nix-channel.cc @@ -192,8 +192,11 @@ static void update(const StringSet & channelNames) if (lstat(nixDefExpr.c_str(), &st) == 0) { if (S_ISLNK(st.st_mode)) // old-skool ~/.nix-defexpr - if (unlink(nixDefExpr.c_str()) == -1) - throw SysError("unlinking %1%", PathFmt(nixDefExpr)); + try { + std::filesystem::remove(nixDefExpr); + } catch (std::filesystem::filesystem_error & e) { + throw SystemError(e.code(), "unlinking %s", PathFmt(nixDefExpr)); + } } else if (errno != ENOENT) { throw SysError("getting status of %1%", PathFmt(nixDefExpr)); } diff --git a/src/nix/nix-instantiate/nix-instantiate.cc b/src/nix/nix-instantiate/nix-instantiate.cc index 6651b2c4530..82838e2ae8a 100644 --- a/src/nix/nix-instantiate/nix-instantiate.cc +++ b/src/nix/nix-instantiate/nix-instantiate.cc @@ -91,7 +91,7 @@ void processExpr( rootName += "-" + std::to_string(rootNr); auto store2 = state.store.dynamic_pointer_cast(); if (store2) - drvPathS = store2->addPermRoot(drvPath, rootName.string()); + drvPathS = store2->addPermRoot(drvPath, rootName).string(); } std::cout << fmt("%s%s\n", drvPathS, (outputName != "out" ? "!" + outputName : "")); } diff --git a/src/nix/nix-store/nix-store.cc b/src/nix/nix-store/nix-store.cc index 1aba51aa68f..9eb80fb0554 100644 --- a/src/nix/nix-store/nix-store.cc +++ b/src/nix/nix-store/nix-store.cc @@ -104,7 +104,7 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) rootName += "-" + std::to_string(rootNr); if (i->first != "out") rootName += "-" + i->first; - retPath = store2->addPermRoot(outPath, rootName.string()); + retPath = store2->addPermRoot(outPath, rootName).string(); } } outputs.insert(retPath); @@ -125,7 +125,7 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) rootNr++; if (rootNr > 1) rootName += "-" + std::to_string(rootNr); - return {store2->addPermRoot(path.path, rootName.string())}; + return {store2->addPermRoot(path.path, rootName).string()}; } } return {store->printStorePath(path.path)}; diff --git a/src/nix/profile.cc b/src/nix/profile.cc index 26c96029827..4f563199c02 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -421,10 +421,10 @@ struct CmdProfileAdd : InstallablesCommand, MixDefaultProfile for (auto it = begin; it != end; it++) { auto & [name, profileElement] = *it; for (auto & storePath : profileElement.storePaths) { - if (conflictError.fileA.starts_with(store->printStorePath(storePath))) { + if (conflictError.fileA.string().starts_with(store->printStorePath(storePath))) { return std::tuple(conflictError.fileA, name, profileElement.toInstallables(*store)); } - if (conflictError.fileB.starts_with(store->printStorePath(storePath))) { + if (conflictError.fileB.string().starts_with(store->printStorePath(storePath))) { return std::tuple(conflictError.fileB, name, profileElement.toInstallables(*store)); } } @@ -462,8 +462,8 @@ struct CmdProfileAdd : InstallablesCommand, MixDefaultProfile "To prioritise the existing package:\n" "\n" " nix profile add %4% --priority %7%\n", - originalConflictingFilePath, - newConflictingFilePath, + PathFmt(originalConflictingFilePath), + PathFmt(newConflictingFilePath), originalEntryName, concatStringsSep(" ", newConflictingRefs), conflictError.priority, diff --git a/tests/functional/nix-profile.sh b/tests/functional/nix-profile.sh index cf84088d761..8d7e05fb355 100755 --- a/tests/functional/nix-profile.sh +++ b/tests/functional/nix-profile.sh @@ -210,11 +210,11 @@ diff -u <( ) <(cat << EOF error: An existing package already provides the following file: - $(nix build --no-link --print-out-paths "${flake1Dir}""#default.out")/bin/hello + "$(nix build --no-link --print-out-paths "${flake1Dir}""#default.out")/bin/hello" This is the conflicting file from the new package: - $(nix build --no-link --print-out-paths "${flake2Dir}""#default.out")/bin/hello + "$(nix build --no-link --print-out-paths "${flake2Dir}""#default.out")/bin/hello" To remove the existing package: