libutil: replace string-based Path with std::filesystem::path across core libraries#15313
Conversation
1d54304 to
73960d1
Compare
73960d1 to
2edf818
Compare
| auto deleteFromStore = [&](std::string_view baseName, bool isKnownPath) { | ||
| Path path = storeDir + "/" + std::string(baseName); | ||
| Path realPath = config->realStoreDir + "/" + std::string(baseName); | ||
| auto realPath = config->realStoreDir.get() / std::string(baseName); |
There was a problem hiding this comment.
Oh we should be incredibly careful with the use of operator/ because if RHS iss absolute everything will blow up and we'll have a thousand CVEs on our hands.
There was a problem hiding this comment.
Yeah that's a good point, here deleteFromStore is only called with either a store path or an entry from readdir, which will only give us the filename component.
| AutoCloseFD tmpDirFd = openDirectory(realPath); | ||
| if (!tmpDirFd || !lockFile(tmpDirFd.get(), ltWrite, false)) { | ||
| debug("skipping locked tempdir '%s'", realPath); | ||
| debug("skipping locked tempdir '%s'", PathFmt(realPath)); |
There was a problem hiding this comment.
| debug("skipping locked tempdir '%s'", PathFmt(realPath)); | |
| debug("skipping locked tempdir %s", PathFmt(realPath)); |
| 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 '%1%'", config->realStoreDir); | ||
| throw SysError("changing ownership of path '%s'", PathFmt(config->realStoreDir.get())); |
There was a problem hiding this comment.
| throw SysError("changing ownership of path '%s'", PathFmt(config->realStoreDir.get())); | |
| throw SysError("changing ownership of path %s", PathFmt(config->realStoreDir.get())); |
| 0600); | ||
| if (!fdGCLock) | ||
| throw SysError("opening global GC lock '%1%'", fnGCLock); | ||
| throw SysError("opening global GC lock '%1%'", PathFmt(fnGCLock)); |
There was a problem hiding this comment.
| throw SysError("opening global GC lock '%1%'", PathFmt(fnGCLock)); | |
| throw SysError("opening global GC lock %1%", PathFmt(fnGCLock)); |
| AutoCloseDir dir(opendir(path.c_str())); | ||
| if (!dir) | ||
| throw SysError("opening directory '%1%'", path); | ||
| throw SysError("opening directory '%s'", PathFmt(path)); |
There was a problem hiding this comment.
| throw SysError("opening directory '%s'", PathFmt(path)); | |
| throw SysError("opening directory %s", PathFmt(path)); |
| } | ||
| if (errno) | ||
| throw SysError("reading directory '%1%'", path); | ||
| throw SysError("reading directory '%s'", PathFmt(path)); |
There was a problem hiding this comment.
| throw SysError("reading directory '%s'", PathFmt(path)); | |
| throw SysError("reading directory %s", PathFmt(path)); |
| if (std::regex_search(path, std::regex("\\.app/Contents/.+$"))) { | ||
| debug("'%1%' is not allowed to be linked in macOS", path); | ||
| if (std::regex_search(path.string(), std::regex("\\.app/Contents/.+$"))) { | ||
| debug("'%s' is not allowed to be linked in macOS", PathFmt(path)); |
There was a problem hiding this comment.
| debug("'%s' is not allowed to be linked in macOS", PathFmt(path)); | |
| debug("%s is not allowed to be linked in macOS", PathFmt(path)); |
| /* 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)", path, st.st_nlink - 2); | ||
| debug("'%s' is already linked, with %d other file(s)", PathFmt(path), st.st_nlink - 2); |
There was a problem hiding this comment.
| 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); |
| .hash; | ||
| }); | ||
| debug("'%1%' has hash '%2%'", path, hash.to_string(HashFormat::Nix32, true)); | ||
| debug("'%s' has hash '%s'", PathFmt(path), hash.to_string(HashFormat::Nix32, true)); |
There was a problem hiding this comment.
| 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)); |
| if (!isInStore(path)) | ||
| throw BadStorePath("path '%1%' is not in the Nix store", path); | ||
| if (!isInStore(path.string())) | ||
| throw BadStorePath("path '%1%' is not in the Nix store", PathFmt(path)); |
There was a problem hiding this comment.
| throw BadStorePath("path '%1%' is not in the Nix store", PathFmt(path)); | |
| throw BadStorePath("path %1% is not in the Nix store", PathFmt(path)); |
|
Sorry I missed those pathfmt quotes @xokdvium |
| } | ||
| } catch (Error & e) { | ||
| e.addTrace({}, "writing file '%1%'", path); | ||
| e.addTrace({}, "writing file '%s'", PathFmt(path)); |
There was a problem hiding this comment.
| e.addTrace({}, "writing file '%s'", PathFmt(path)); | |
| e.addTrace({}, "writing file %s", PathFmt(path)); |
| AutoCloseFD fd = toDescriptor(open(path.parent_path().c_str(), O_RDONLY, 0)); | ||
| if (!fd) | ||
| throw SysError("opening file '%1%'", path); | ||
| throw SysError("opening file '%s'", PathFmt(path)); |
There was a problem hiding this comment.
| throw SysError("opening file '%s'", PathFmt(path)); | |
| throw SysError("opening file %s", PathFmt(path)); |
| AutoCloseFD fd = toDescriptor(open(path.string().c_str(), O_RDONLY, 0)); | ||
| if (!fd) | ||
| throw SysError("opening file '%1%'", path); | ||
| throw SysError("opening file '%s'", PathFmt(path)); |
There was a problem hiding this comment.
| throw SysError("opening file '%s'", PathFmt(path)); | |
| throw SysError("opening file %s", PathFmt(path)); |
| ) | ||
| == -1) | ||
| throw SysError("creating directory '%1%'", path); | ||
| throw SysError("creating directory '%s'", PathFmt(path)); |
There was a problem hiding this comment.
| throw SysError("creating directory '%s'", PathFmt(path)); | |
| throw SysError("creating directory %s", PathFmt(path)); |
| std::pair<AutoCloseFD, std::filesystem::path> createTempFile(const std::filesystem::path & prefix) | ||
| { | ||
| Path tmpl(defaultTempDir().string() + "/" + prefix + ".XXXXXX"); | ||
| std::filesystem::path tmpl(defaultTempDir() / (prefix.string() + ".XXXXXX")); |
There was a problem hiding this comment.
What if prefix is an absolute path? Please add an assert at least
There was a problem hiding this comment.
Yeah good point, as of now prefix is always a hardcoded literal (like nix-shell) but an assert would be good here.
| static std::atomic<uint32_t> counter(std::random_device{}()); | ||
| auto tmpRoot = canonPath(root.empty() ? defaultTempDir().string() : root.string(), true); | ||
| return fmt("%1%/%2%-%3%-%4%", tmpRoot, suffix, getpid(), counter.fetch_add(1, std::memory_order_relaxed)); | ||
| return tmpRoot / fmt("%s-%s-%s", suffix, getpid(), counter.fetch_add(1, std::memory_order_relaxed)); |
There was a problem hiding this comment.
What if suffix is an absolute path? This will discard LHS
| { | ||
| auto setUpdateLock = [&](auto && fileName) { | ||
| uploadLock = openLockFile(currentLoad + "/" + escapeUri(fileName) + ".upload-lock", true); | ||
| uploadLock = openLockFile(currentLoad / (escapeUri(fileName) + ".upload-lock"), true); |
There was a problem hiding this comment.
Can escapeUri return an absolute path?
There was a problem hiding this comment.
no it replaces all instances of / with _
Drop single quotes around PathFmt format args in error and debug messages across gc.cc, local-store.cc, optimise-store.cc, store-api.cc, and file-system.cc; PathFmt already handles presentation so the extra quoting is redundant. Add an assert in createTempFile that prefix is not absolute, since operator/ silently discards LHS when RHS is absolute.
- file-system: drop redundant quotes around `PathFmt` and assert relative paths - libutil, libstore: fix mingw cross-compilation breakages
- file-system: drop redundant quotes around `PathFmt` and assert relative paths - libutil, libstore: fix mingw cross-compilation breakages
- file-system: drop redundant quotes around `PathFmt` and assert relative paths - libutil, libstore: fix mingw cross-compilation breakages
| const auto & localSettings = config->getLocalSettings(); | ||
| const auto & gcSettings = localSettings.getGCSettings(); | ||
| createDirs(gcRootsDir); | ||
| if (!pathExists(gcRootsDir)) { |
libutil: replace string-based Path with std::filesystem::path across core libraries
- file-system: drop redundant quotes around `PathFmt` and assert relative paths - libutil, libstore: fix mingw cross-compilation breakages
Motivation
This takes the
std::filesystem::pathmigration from the CLI layer into the core libraries (libutil, libstore, libexpr, libfetchers, libflake), converting function signatures, settings fields, and locals throughoutfile-system.hh,archive.hh,configuration.hh, and their implementations.PathSettingbecomesSetting<std::filesystem::path>inlocal-overlay-store.hhandlocal-store.hhwith.get()calls at use sites, and severalwriteFileoverloads collapse now that thePath-based wrappers infile-system.hhare gone.Context
Pathtostd::filesystem::pathin CLI commands #15312Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.