Fix issues from #15313

- file-system: drop redundant quotes around `PathFmt` and assert relative paths
- libutil, libstore: fix mingw cross-compilation breakages
This commit is contained in:
Amaan Qureshi
2026-02-24 15:13:28 -05:00
parent cf1ead7872
commit f4dfbca04d
21 changed files with 71 additions and 63 deletions

View File

@@ -125,7 +125,7 @@ ReadlineLikeInteracter::Guard ReadlineLikeInteracter::init(detail::ReplCompleter
#if !USE_READLINE
el_hist_size = 1000;
#endif
read_history(historyFile.c_str());
read_history(historyFile.string().c_str());
auto oldRepl = curRepl;
curRepl = repl;
Guard restoreRepl([oldRepl] { curRepl = oldRepl; });
@@ -208,7 +208,7 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT
ReadlineLikeInteracter::~ReadlineLikeInteracter()
{
write_history(historyFile.c_str());
write_history(historyFile.string().c_str());
}
}; // namespace nix

View File

@@ -560,7 +560,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
auto localStore = state->store.dynamic_pointer_cast<LocalFSStore>();
if (localStore && command == ":bl") {
std::string symlink = "repl-result-" + outputName;
localStore->addPermRoot(outputPath, absPath(symlink));
localStore->addPermRoot(outputPath, absPath(symlink).string());
logger->cout(" ./%s -> %s", symlink, state->store->printStorePath(outputPath));
} else {
logger->cout(" %s -> %s", outputName, state->store->printStorePath(outputPath));

View File

@@ -76,7 +76,7 @@ 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);
auto target = canonPath(dstFile, true).string();
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)
@@ -104,7 +104,7 @@ 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), srcFile, priority);
throw BuildEnvFileConflictError(readLink(dstFile).string(), srcFile, priority);
if (prevPriority < priority)
continue;
if (unlink(dstFile.c_str()) == -1)

View File

@@ -680,7 +680,7 @@ 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<StorePath>::read(*store, rconn);
Path gcRoot = absPath(readString(conn.from));
Path gcRoot = absPath(readString(conn.from)).string();
logger->startWork();
auto & localFSStore = require<LocalFSStore>(*store);
localFSStore.addPermRoot(storePath, gcRoot);
@@ -690,7 +690,7 @@ static void performOp(
}
case WorkerProto::Op::AddIndirectRoot: {
Path path = absPath(readString(conn.from));
Path path = absPath(readString(conn.from)).string();
logger->startWork();
auto & indirectRootStore = require<IndirectRootStore>(*store);

View File

@@ -41,7 +41,7 @@ static std::string gcRootsDir = "gcroots";
void LocalStore::addIndirectRoot(const Path & path)
{
std::string hash = hashString(HashAlgorithm::SHA1, path).to_string(HashFormat::Nix32, false);
Path realRoot = canonPath((config->stateDir.get() / gcRootsDir / "auto" / hash).string());
Path realRoot = canonPath((config->stateDir.get() / gcRootsDir / "auto" / hash).string()).string();
makeSymlink(realRoot, path);
}
@@ -57,7 +57,7 @@ void LocalStore::createTempRootsFile()
if (pathExists(fnTempRoots))
/* It *must* be stale, since there can be no two
processes with the same pid. */
unlink(fnTempRoots.c_str());
unlink(fnTempRoots.string().c_str());
*fdTempRoots = openLockFile(fnTempRoots, true);
@@ -236,14 +236,14 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
}
else if (type == std::filesystem::file_type::symlink) {
Path target = readLink(path);
Path target = readLink(path).string();
if (isInStore(target))
foundRoot(path, target);
/* Handle indirect roots. */
else {
auto parentPath = std::filesystem::path(path).parent_path();
target = absPath(target, &parentPath);
target = absPath(target, &parentPath).string();
if (!pathExists(target)) {
if (isInDir(path, std::filesystem::path{config->stateDir.get()} / gcRootsDir / "auto")) {
printInfo("removing stale link from '%1%' to '%2%'", path, target);
@@ -252,7 +252,7 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
} else {
if (!std::filesystem::is_symlink(target))
return;
Path target2 = readLink(target);
Path target2 = readLink(target).string();
if (isInStore(target2))
foundRoot(target, target2);
}
@@ -408,7 +408,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
throw UnimplementedError("External GC client not implemented yet");
#else
if (fcntl(fdServer.get(), F_SETFL, fcntl(fdServer.get(), F_GETFL) | O_NONBLOCK) == -1)
throw SysError("making socket '%s' non-blocking", PathFmt(socketPath));
throw SysError("making socket %s non-blocking", PathFmt(socketPath));
Pipe shutdownPipe;
shutdownPipe.create();
@@ -539,6 +539,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
/* Helper function that deletes a path from the store and throws
GCLimitReached if we've deleted enough garbage. */
auto deleteFromStore = [&](std::string_view baseName, bool isKnownPath) {
assert(!std::filesystem::path(baseName).is_absolute());
Path path = storeDir + "/" + std::string(baseName);
auto realPath = config->realStoreDir.get() / std::string(baseName);
@@ -548,7 +549,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (baseName.find("tmp-", 0) == 0) {
AutoCloseFD tmpDirFd = openDirectory(realPath);
if (!tmpDirFd || !lockFile(tmpDirFd.get(), ltWrite, false)) {
debug("skipping locked tempdir '%s'", PathFmt(realPath));
debug("skipping locked tempdir %s", PathFmt(realPath));
return;
}
}
@@ -713,7 +714,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
printInfo("determining live/dead paths...");
try {
AutoCloseDir dir(opendir(config->realStoreDir.get().c_str()));
AutoCloseDir dir(opendir(config->realStoreDir.get().string().c_str()));
if (!dir)
throw SysError("opening directory %1%", PathFmt(config->realStoreDir.get()));
@@ -757,7 +758,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) {
printInfo("deleting unused links...");
AutoCloseDir dir(opendir(linksDir.c_str()));
AutoCloseDir dir(opendir(linksDir.string().c_str()));
if (!dir)
throw SysError("opening directory %1%", PathFmt(linksDir));
@@ -769,7 +770,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
std::string name = dirent->d_name;
if (name == "." || name == "..")
continue;
Path path = linksDir + "/" + name;
Path path = (linksDir / name).string();
auto st = lstat(path);

View File

@@ -53,18 +53,24 @@ public:
Setting<std::filesystem::path> stateDir{
this,
rootDir.get() ? *rootDir.get() + "/nix/var/nix" : getDefaultStateDir(),
rootDir.get() ? *rootDir.get() / "nix/var/nix" : std::filesystem::path(getDefaultStateDir()),
"state",
"Directory where Nix stores state."};
"Directory where Nix stores state.",
};
Setting<std::filesystem::path> logDir{
this,
rootDir.get() ? *rootDir.get() + "/nix/var/log/nix" : getDefaultLogDir(),
rootDir.get() ? *rootDir.get() / "nix/var/log/nix" : std::filesystem::path(getDefaultLogDir()),
"log",
"directory where Nix stores log files."};
"directory where Nix stores log files.",
};
Setting<std::filesystem::path> realStoreDir{
this, rootDir.get() ? *rootDir.get() + "/nix/store" : storeDir, "real", "Physical path of the Nix store."};
this,
rootDir.get() ? *rootDir.get() / "nix/store" : std::filesystem::path(storeDir),
"real",
"Physical path of the Nix store.",
};
};
struct alignas(8) /* Work around ASAN failures on i686-linux. */
@@ -114,7 +120,7 @@ struct alignas(8) /* Work around ASAN failures on i686-linux. */
Path toRealPath(const Path & storePath)
{
assert(isInStore(storePath));
return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
return (getRealStoreDir() / std::string(storePath, storeDir.size() + 1)).string();
}
std::optional<std::string> getBuildLogExact(const StorePath & path) override;

View File

@@ -17,7 +17,7 @@ void IndirectRootStore::makeSymlink(const Path & link, const Path & target)
Path IndirectRootStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot)
{
Path gcRoot(canonPath(_gcRoot));
Path gcRoot(canonPath(_gcRoot).string());
if (isInStore(gcRoot))
throw Error(

View File

@@ -30,7 +30,8 @@ LocalFSStoreConfig::LocalFSStoreConfig(PathView rootDir, const Params & params)
*/
, rootDir{makeRootDirSetting(
*this,
!rootDir.empty() && params.count("root") == 0 ? std::optional<Path>{canonPath(rootDir)} : std::nullopt)}
!rootDir.empty() && params.count("root") == 0 ? std::optional<Path>{canonPath(rootDir).string()}
: std::nullopt)}
{
}

View File

@@ -207,7 +207,7 @@ void LocalOverlayStore::collectGarbage(const GCOptions & options, GCResults & re
void LocalOverlayStore::deleteStorePath(const Path & path, uint64_t & bytesFreed, bool isKnownPath)
{
auto mergedDir = config->realStoreDir.get() + "/";
auto mergedDir = config->realStoreDir.get().string() + "/";
if (path.substr(0, mergedDir.length()) != mergedDir) {
warn("local-overlay: unexpected gc path '%s' ", path);
return;
@@ -261,7 +261,7 @@ LocalStore::VerificationResult LocalOverlayStore::verifyAllValidPaths(RepairFlag
StorePathSet done;
auto existsInStoreDir = [&](const StorePath & storePath) {
return pathExists(config->realStoreDir.get() + "/" + storePath.to_string());
return pathExists((config->realStoreDir.get() / storePath.to_string()).string());
};
bool errors = false;

View File

@@ -175,7 +175,7 @@ LocalStore::LocalStore(ref<const Config> config)
if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
if (chown(config->realStoreDir.get().c_str(), 0, gr->gr_gid) == -1)
throw SysError("changing ownership of path '%s'", PathFmt(config->realStoreDir.get()));
throw SysError("changing ownership of path %s", PathFmt(config->realStoreDir.get()));
chmod(config->realStoreDir.get(), perm);
}
}
@@ -204,7 +204,7 @@ LocalStore::LocalStore(ref<const Config> config)
auto st = maybeStat(reservedPath);
if (!st || st->st_size != gcSettings.reservedSize) {
AutoCloseFD fd = toDescriptor(open(
reservedPath.c_str(),
reservedPath.string().c_str(),
O_WRONLY | O_CREAT
#ifndef _WIN32
| O_CLOEXEC
@@ -397,7 +397,7 @@ AutoCloseFD LocalStore::openGCLock()
{
auto fnGCLock = config->stateDir.get() / "gc.lock";
auto fdGCLock = open(
fnGCLock.c_str(),
fnGCLock.string().c_str(),
O_RDWR | O_CREAT
#ifndef _WIN32
| O_CLOEXEC
@@ -405,7 +405,7 @@ AutoCloseFD LocalStore::openGCLock()
,
0600);
if (!fdGCLock)
throw SysError("opening global GC lock '%1%'", PathFmt(fnGCLock));
throw SysError("opening global GC lock %1%", PathFmt(fnGCLock));
return toDescriptor(fdGCLock);
}
@@ -450,7 +450,7 @@ LocalStore::~LocalStore()
auto fdTempRoots(_fdTempRoots.lock());
if (*fdTempRoots) {
fdTempRoots->close();
unlink(fnTempRoots.c_str());
unlink(fnTempRoots.string().c_str());
}
} catch (...) {
ignoreExceptionInDestructor();
@@ -502,7 +502,7 @@ void LocalStore::openDB(State & state, bool create)
throw Error("cannot create database while in read-only mode");
}
if (access(dbDir.c_str(), R_OK | (config->readOnly ? 0 : W_OK)))
if (access(dbDir.string().c_str(), R_OK | (config->readOnly ? 0 : W_OK)))
throw SysError("Nix database directory %1% is not writable", PathFmt(dbDir));
/* Open the Nix database. */

View File

@@ -50,7 +50,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
debug("loading hash inodes in memory");
InodeHash inodeHash;
AutoCloseDir dir(opendir(linksDir.c_str()));
AutoCloseDir dir(opendir(linksDir.string().c_str()));
if (!dir)
throw SysError("opening directory %1%", PathFmt(linksDir));
@@ -72,9 +72,9 @@ Strings LocalStore::readDirectoryIgnoringInodes(const std::filesystem::path & pa
{
Strings names;
AutoCloseDir dir(opendir(path.c_str()));
AutoCloseDir dir(opendir(path.string().c_str()));
if (!dir)
throw SysError("opening directory '%s'", PathFmt(path));
throw SysError("opening directory %s", PathFmt(path));
struct dirent * dirent;
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
@@ -91,7 +91,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const std::filesystem::path & pa
names.push_back(name);
}
if (errno)
throw SysError("reading directory '%s'", PathFmt(path));
throw SysError("reading directory %s", PathFmt(path));
return names;
}
@@ -111,7 +111,7 @@ void LocalStore::optimisePath_(
https://github.com/NixOS/nix/pull/2230 for more discussion. */
if (std::regex_search(path.string(), std::regex("\\.app/Contents/.+$"))) {
debug("'%s' is not allowed to be linked in macOS", PathFmt(path));
debug("%s is not allowed to be linked in macOS", PathFmt(path));
return;
}
#endif
@@ -142,7 +142,7 @@ void LocalStore::optimisePath_(
/* This can still happen on top-level files. */
if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) {
debug("'%s' is already linked, with %d other file(s)", PathFmt(path), st.st_nlink - 2);
debug("%s is already linked, with %d other file(s)", PathFmt(path), st.st_nlink - 2);
return;
}
@@ -162,7 +162,7 @@ void LocalStore::optimisePath_(
HashAlgorithm::SHA256)
.hash;
});
debug("'%s' has hash '%s'", PathFmt(path), hash.to_string(HashFormat::Nix32, true));
debug("%s has hash '%s'", PathFmt(path), hash.to_string(HashFormat::Nix32, true));
/* Check if this is a known hash. */
std::filesystem::path linkPath = std::filesystem::path{linksDir} / hash.to_string(HashFormat::Nix32, false);

View File

@@ -84,7 +84,7 @@ std::filesystem::path Store::followLinksToStore(std::string_view _path) const
}
if (!isInStore(path.string()))
throw BadStorePath("path '%1%' is not in the Nix store", PathFmt(path));
throw BadStorePath("path %1% is not in the Nix store", PathFmt(path));
return path;
}

View File

@@ -15,7 +15,7 @@ StorePath StoreDirConfig::parseStorePath(std::string_view path) const
// Windows <-> Unix ssh-ing).
auto p =
#ifdef _WIN32
path
std::filesystem::path(path)
#else
canonPath(std::string(path))
#endif

View File

@@ -55,7 +55,7 @@ void ExecutablePath::parseAppend(const OsString & path)
OsString ExecutablePath::render() const
{
std::vector<PathView> path2;
std::vector<OsStringView> path2;
path2.reserve(directories.size());
for (auto & p : directories)
path2.push_back(p.native());

View File

@@ -595,29 +595,25 @@ AutoCloseFD createAnonymousTempFile()
std::pair<AutoCloseFD, std::filesystem::path> createTempFile(const std::filesystem::path & prefix)
{
std::filesystem::path tmpl(defaultTempDir() / (prefix.string() + ".XXXXXX"));
// Strictly speaking, this is UB, but who cares...
assert(!prefix.is_absolute());
auto tmpl = (defaultTempDir() / (prefix.string() + ".XXXXXX")).string();
// FIXME: use O_TMPFILE.
AutoCloseFD fd = toDescriptor(
#ifdef _WIN32
_wmkstemp(tmpl.c_str())
#else
mkstemp(const_cast<char *>(tmpl.c_str()))
#endif
);
// `mkstemp` modifies the string to contain the actual filename.
AutoCloseFD fd = toDescriptor(mkstemp(tmpl.data()));
if (!fd)
throw SysError("creating temporary file %s", PathFmt(tmpl));
throw SysError("creating temporary file '%s'", tmpl);
#ifndef _WIN32
unix::closeOnExec(fd.get());
#endif
return {std::move(fd), tmpl};
return {std::move(fd), std::filesystem::path(std::move(tmpl))};
}
std::filesystem::path makeTempPath(const std::filesystem::path & root, const std::string & suffix)
{
// start the counter at a random value to minimize issues with preexisting temp paths
static std::atomic<uint32_t> counter(std::random_device{}());
assert(!std::filesystem::path(suffix).is_absolute());
auto tmpRoot = canonPath(root.empty() ? defaultTempDir().string() : root.string(), true);
return tmpRoot / fmt("%s-%s-%s", suffix, getpid(), counter.fetch_add(1, std::memory_order_relaxed));
}

View File

@@ -182,7 +182,7 @@ std::string PosixSourceAccessor::readLink(const CanonPath & path)
{
if (auto parent = path.parent())
assertNoSymlinks(*parent);
return nix::readLink(makeAbsPath(path).string());
return nix::readLink(makeAbsPath(path).string()).string();
}
std::optional<std::filesystem::path> PosixSourceAccessor::getPhysicalPath(const CanonPath & path)

View File

@@ -36,7 +36,7 @@ AutoCloseFD createUnixDomainSocket(const std::filesystem::path & path, mode_t mo
{
auto fdSocket = nix::createUnixDomainSocket();
bind(fdSocket.get(), path);
bind(toSocket(fdSocket.get()), path);
chmod(path, mode);
@@ -72,7 +72,7 @@ bindConnectProcHelper(std::string_view operationName, auto && operation, Socket
try {
pipe.readSide.close();
auto dir = std::filesystem::path(path).parent_path();
if (chdir(dir.c_str()) == -1)
if (chdir(dir.string().c_str()) == -1)
throw SysError("chdir to %s failed", PathFmt(dir));
std::string base(baseNameOf(path));
if (base.size() + 1 >= sizeof(addr.sun_path))
@@ -105,7 +105,7 @@ bindConnectProcHelper(std::string_view operationName, auto && operation, Socket
void bind(Socket fd, const std::filesystem::path & path)
{
unlink(path.c_str());
unlink(path.string().c_str());
bindConnectProcHelper("bind", ::bind, fd, path.string());
}

View File

@@ -9,7 +9,7 @@
namespace nix {
static std::optional<std::filesystem::path> maybePath(PathView path)
std::optional<std::filesystem::path> maybePath(PathView path)
{
if (path.length() >= 3 && (('A' <= path[0] && path[0] <= 'Z') || ('a' <= path[0] && path[0] <= 'z'))
&& path[1] == ':' && WindowsPathTrait<char>::isPathSep(path[2])) {

View File

@@ -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));
store2->addPermRoot(outputPath, absPath(symlink).string());
}
outPaths.push_back(outputPath);

View File

@@ -38,7 +38,7 @@ void removeOldGenerations(std::filesystem::path dir)
if (type == std::filesystem::file_type::symlink && canWrite) {
std::string link;
try {
link = readLink(path);
link = readLink(path).string();
} catch (SystemError & e) {
if (e.is(std::errc::no_such_file_or_directory))
continue;

View File

@@ -81,11 +81,15 @@ void execProgramInStore(
if (store->storeDir != store2->getRealStoreDir()) {
Strings helperArgs = {
chrootHelperName, store->storeDir, store2->getRealStoreDir(), std::string(system.value_or("")), program};
chrootHelperName,
store->storeDir,
store2->getRealStoreDir().string(),
std::string(system.value_or("")),
program};
for (auto & arg : args)
helperArgs.push_back(arg);
execve(getSelfExe().value_or("nix").c_str(), stringsToCharPtrs(helperArgs).data(), envp);
execve(getSelfExe().value_or("nix").string().c_str(), stringsToCharPtrs(helperArgs).data(), envp);
throw SysError("could not execute chroot helper");
}