mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-10 08:16:15 +02:00
Merge pull request #10658 from nix-windows/more-std-filesystem
Use `std::filesystem` functions in more places
This commit is contained in:
commit
9ae6455b0e
21 changed files with 127 additions and 151 deletions
|
@ -63,7 +63,6 @@ AC_SYS_LARGEFILE
|
||||||
|
|
||||||
|
|
||||||
# Solaris-specific stuff.
|
# Solaris-specific stuff.
|
||||||
AC_STRUCT_DIRENT_D_TYPE
|
|
||||||
case "$host_os" in
|
case "$host_os" in
|
||||||
solaris*)
|
solaris*)
|
||||||
# Solaris requires -lsocket -lnsl for network functions
|
# Solaris requires -lsocket -lnsl for network functions
|
||||||
|
|
|
@ -260,10 +260,12 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
|
||||||
auto dir = std::string(cur, 0, slash);
|
auto dir = std::string(cur, 0, slash);
|
||||||
auto prefix2 = std::string(cur, slash + 1);
|
auto prefix2 = std::string(cur, slash + 1);
|
||||||
for (auto & entry : readDirectory(dir == "" ? "/" : dir)) {
|
for (auto & entry : readDirectory(dir == "" ? "/" : dir)) {
|
||||||
if (entry.name[0] != '.' && hasPrefix(entry.name, prefix2))
|
auto name = entry.path().filename().string();
|
||||||
completions.insert(prev + dir + "/" + entry.name);
|
if (name[0] != '.' && hasPrefix(name, prefix2))
|
||||||
|
completions.insert(prev + entry.path().string());
|
||||||
}
|
}
|
||||||
} catch (Error &) {
|
} catch (Error &) {
|
||||||
|
} catch (std::filesystem::filesystem_error &) {
|
||||||
}
|
}
|
||||||
} else if ((dot = cur.rfind('.')) == std::string::npos) {
|
} else if ((dot = cur.rfind('.')) == std::string::npos) {
|
||||||
/* This is a variable name; look it up in the current scope. */
|
/* This is a variable name; look it up in the current scope. */
|
||||||
|
|
|
@ -17,12 +17,12 @@ struct State
|
||||||
/* For each activated package, create symlinks */
|
/* 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 Path & srcDir, const Path & dstDir, int priority)
|
||||||
{
|
{
|
||||||
DirEntries srcFiles;
|
std::vector<std::filesystem::directory_entry> srcFiles;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
srcFiles = readDirectory(srcDir);
|
srcFiles = readDirectory(srcDir);
|
||||||
} catch (SysError & e) {
|
} catch (std::filesystem::filesystem_error & e) {
|
||||||
if (e.errNo == ENOTDIR) {
|
if (e.code() == 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", srcDir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,12 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto & ent : srcFiles) {
|
for (const auto & ent : srcFiles) {
|
||||||
if (ent.name[0] == '.')
|
auto name = ent.path().filename();
|
||||||
|
if (name.string()[0] == '.')
|
||||||
/* not matched by glob */
|
/* not matched by glob */
|
||||||
continue;
|
continue;
|
||||||
auto srcFile = srcDir + "/" + ent.name;
|
auto srcFile = (std::filesystem::path{srcDir} / name).string();
|
||||||
auto dstFile = dstDir + "/" + ent.name;
|
auto dstFile = (std::filesystem::path{dstDir} / name).string();
|
||||||
|
|
||||||
struct stat srcSt;
|
struct stat srcSt;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -343,13 +343,13 @@ void initPlugins()
|
||||||
{
|
{
|
||||||
assert(!settings.pluginFiles.pluginsLoaded);
|
assert(!settings.pluginFiles.pluginsLoaded);
|
||||||
for (const auto & pluginFile : settings.pluginFiles.get()) {
|
for (const auto & pluginFile : settings.pluginFiles.get()) {
|
||||||
Paths pluginFiles;
|
std::vector<std::filesystem::path> pluginFiles;
|
||||||
try {
|
try {
|
||||||
auto ents = readDirectory(pluginFile);
|
auto ents = readDirectory(pluginFile);
|
||||||
for (const auto & ent : ents)
|
for (const auto & ent : ents)
|
||||||
pluginFiles.emplace_back(pluginFile + "/" + ent.name);
|
pluginFiles.emplace_back(ent.path());
|
||||||
} catch (SysError & e) {
|
} catch (std::filesystem::filesystem_error & e) {
|
||||||
if (e.errNo != ENOTDIR)
|
if (e.code() != std::errc::not_a_directory)
|
||||||
throw;
|
throw;
|
||||||
pluginFiles.emplace_back(pluginFile);
|
pluginFiles.emplace_back(pluginFile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,11 +84,12 @@ protected:
|
||||||
StorePathSet paths;
|
StorePathSet paths;
|
||||||
|
|
||||||
for (auto & entry : readDirectory(binaryCacheDir)) {
|
for (auto & entry : readDirectory(binaryCacheDir)) {
|
||||||
if (entry.name.size() != 40 ||
|
auto name = entry.path().filename().string();
|
||||||
!hasSuffix(entry.name, ".narinfo"))
|
if (name.size() != 40 ||
|
||||||
|
!hasSuffix(name, ".narinfo"))
|
||||||
continue;
|
continue;
|
||||||
paths.insert(parseStorePath(
|
paths.insert(parseStorePath(
|
||||||
storeDir + "/" + entry.name.substr(0, entry.name.size() - 8)
|
storeDir + "/" + name.substr(0, name.size() - 8)
|
||||||
+ "-" + MissingName));
|
+ "-" + MissingName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,12 @@ std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path pro
|
||||||
{
|
{
|
||||||
Generations gens;
|
Generations gens;
|
||||||
|
|
||||||
Path profileDir = dirOf(profile);
|
std::filesystem::path profileDir = dirOf(profile);
|
||||||
auto profileName = std::string(baseNameOf(profile));
|
auto profileName = std::string(baseNameOf(profile));
|
||||||
|
|
||||||
for (auto & i : readDirectory(profileDir)) {
|
for (auto & i : readDirectory(profileDir.string())) {
|
||||||
if (auto n = parseName(profileName, i.name)) {
|
if (auto n = parseName(profileName, i.path().filename().string())) {
|
||||||
auto path = profileDir + "/" + i.name;
|
auto path = i.path().string();
|
||||||
gens.push_back({
|
gens.push_back({
|
||||||
.number = *n,
|
.number = *n,
|
||||||
.path = path,
|
.path = path,
|
||||||
|
@ -338,6 +338,8 @@ Path getDefaultProfile()
|
||||||
return absPath(readLink(profileLink), dirOf(profileLink));
|
return absPath(readLink(profileLink), dirOf(profileLink));
|
||||||
} catch (Error &) {
|
} catch (Error &) {
|
||||||
return profileLink;
|
return profileLink;
|
||||||
|
} catch (std::filesystem::filesystem_error &) {
|
||||||
|
return profileLink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ void builtinUnpackChannel(
|
||||||
auto entries = readDirectory(out);
|
auto entries = readDirectory(out);
|
||||||
if (entries.size() != 1)
|
if (entries.size() != 1)
|
||||||
throw Error("channel tarball '%s' contains more than one file", src);
|
throw Error("channel tarball '%s' contains more than one file", src);
|
||||||
renameFile((out + "/" + entries[0].name), (out + "/" + channelName));
|
renameFile(entries[0].path().string(), (out + "/" + channelName));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,14 +160,15 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
|
||||||
/* Read the `temproots' directory for per-process temporary root
|
/* Read the `temproots' directory for per-process temporary root
|
||||||
files. */
|
files. */
|
||||||
for (auto & i : readDirectory(tempRootsDir)) {
|
for (auto & i : readDirectory(tempRootsDir)) {
|
||||||
if (i.name[0] == '.') {
|
auto name = i.path().filename().string();
|
||||||
|
if (name[0] == '.') {
|
||||||
// Ignore hidden files. Some package managers (notably portage) create
|
// Ignore hidden files. Some package managers (notably portage) create
|
||||||
// those to keep the directory alive.
|
// those to keep the directory alive.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Path path = tempRootsDir + "/" + i.name;
|
Path path = i.path();
|
||||||
|
|
||||||
pid_t pid = std::stoi(i.name);
|
pid_t pid = std::stoi(name);
|
||||||
|
|
||||||
debug("reading temporary root file '%1%'", path);
|
debug("reading temporary root file '%1%'", path);
|
||||||
AutoCloseFD fd(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666));
|
AutoCloseFD fd(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666));
|
||||||
|
@ -203,7 +204,7 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, Roots & roots)
|
||||||
{
|
{
|
||||||
auto foundRoot = [&](const Path & path, const Path & target) {
|
auto foundRoot = [&](const Path & path, const Path & target) {
|
||||||
try {
|
try {
|
||||||
|
@ -217,15 +218,15 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (type == DT_UNKNOWN)
|
if (type == std::filesystem::file_type::unknown)
|
||||||
type = getFileType(path);
|
type = getFileType(path);
|
||||||
|
|
||||||
if (type == DT_DIR) {
|
if (type == std::filesystem::file_type::directory) {
|
||||||
for (auto & i : readDirectory(path))
|
for (auto & i : readDirectory(path))
|
||||||
findRoots(path + "/" + i.name, i.type, roots);
|
findRoots(i.path().string(), i.symlink_status().type(), roots);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == DT_LNK) {
|
else if (type == std::filesystem::file_type::symlink) {
|
||||||
Path target = readLink(path);
|
Path target = readLink(path);
|
||||||
if (isInStore(target))
|
if (isInStore(target))
|
||||||
foundRoot(path, target);
|
foundRoot(path, target);
|
||||||
|
@ -247,7 +248,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == DT_REG) {
|
else if (type == std::filesystem::file_type::regular) {
|
||||||
auto storePath = maybeParseStorePath(storeDir + "/" + std::string(baseNameOf(path)));
|
auto storePath = maybeParseStorePath(storeDir + "/" + std::string(baseNameOf(path)));
|
||||||
if (storePath && isValidPath(*storePath))
|
if (storePath && isValidPath(*storePath))
|
||||||
roots[std::move(*storePath)].emplace(path);
|
roots[std::move(*storePath)].emplace(path);
|
||||||
|
@ -255,6 +256,14 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (std::filesystem::filesystem_error & e) {
|
||||||
|
/* 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);
|
||||||
|
else
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
catch (SysError & e) {
|
catch (SysError & e) {
|
||||||
/* We only ignore permanent failures. */
|
/* We only ignore permanent failures. */
|
||||||
if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR)
|
if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR)
|
||||||
|
@ -268,8 +277,8 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||||
void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
|
void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
|
||||||
{
|
{
|
||||||
/* Process direct roots in {gcroots,profiles}. */
|
/* Process direct roots in {gcroots,profiles}. */
|
||||||
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
|
findRoots(stateDir + "/" + gcRootsDir, std::filesystem::file_type::unknown, roots);
|
||||||
findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
|
findRoots(stateDir + "/profiles", std::filesystem::file_type::unknown, roots);
|
||||||
|
|
||||||
/* Add additional roots returned by different platforms-specific
|
/* Add additional roots returned by different platforms-specific
|
||||||
heuristics. This is typically used to add running programs to
|
heuristics. This is typically used to add running programs to
|
||||||
|
|
|
@ -1388,15 +1388,16 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
|
||||||
printInfo("checking link hashes...");
|
printInfo("checking link hashes...");
|
||||||
|
|
||||||
for (auto & link : readDirectory(linksDir)) {
|
for (auto & link : readDirectory(linksDir)) {
|
||||||
printMsg(lvlTalkative, "checking contents of '%s'", link.name);
|
auto name = link.path().filename();
|
||||||
Path linkPath = linksDir + "/" + link.name;
|
printMsg(lvlTalkative, "checking contents of '%s'", name);
|
||||||
|
Path linkPath = linksDir / name;
|
||||||
PosixSourceAccessor accessor;
|
PosixSourceAccessor accessor;
|
||||||
std::string hash = hashPath(
|
std::string hash = hashPath(
|
||||||
{getFSSourceAccessor(), CanonPath(linkPath)},
|
{getFSSourceAccessor(), CanonPath(linkPath)},
|
||||||
FileIngestionMethod::Recursive, HashAlgorithm::SHA256).to_string(HashFormat::Nix32, false);
|
FileIngestionMethod::Recursive, HashAlgorithm::SHA256).to_string(HashFormat::Nix32, false);
|
||||||
if (hash != link.name) {
|
if (hash != name.string()) {
|
||||||
printError("link '%s' was modified! expected hash '%s', got '%s'",
|
printError("link '%s' was modified! expected hash '%s', got '%s'",
|
||||||
linkPath, link.name, hash);
|
linkPath, name, hash);
|
||||||
if (repair) {
|
if (repair) {
|
||||||
if (unlink(linkPath.c_str()) == 0)
|
if (unlink(linkPath.c_str()) == 0)
|
||||||
printInfo("removed link '%s'", linkPath);
|
printInfo("removed link '%s'", linkPath);
|
||||||
|
@ -1483,7 +1484,7 @@ LocalStore::VerificationResult LocalStore::verifyAllValidPaths(RepairFlag repair
|
||||||
*/
|
*/
|
||||||
for (auto & i : readDirectory(realStoreDir)) {
|
for (auto & i : readDirectory(realStoreDir)) {
|
||||||
try {
|
try {
|
||||||
storePathsInStoreDir.insert({i.name});
|
storePathsInStoreDir.insert({i.path().filename().string()});
|
||||||
} catch (BadStorePath &) { }
|
} catch (BadStorePath &) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -371,7 +371,7 @@ private:
|
||||||
PathSet queryValidPathsOld();
|
PathSet queryValidPathsOld();
|
||||||
ValidPathInfo queryPathInfoOld(const Path & path);
|
ValidPathInfo queryPathInfoOld(const Path & path);
|
||||||
|
|
||||||
void findRoots(const Path & path, unsigned char type, Roots & roots);
|
void findRoots(const Path & path, std::filesystem::file_type type, Roots & roots);
|
||||||
|
|
||||||
void findRootsNoTemp(Roots & roots, bool censor);
|
void findRootsNoTemp(Roots & roots, bool censor);
|
||||||
|
|
||||||
|
|
|
@ -136,9 +136,9 @@ static void canonicalisePathMetaData_(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
DirEntries entries = readDirectory(path);
|
std::vector<std::filesystem::directory_entry> entries = readDirectory(path);
|
||||||
for (auto & i : entries)
|
for (auto & i : entries)
|
||||||
canonicalisePathMetaData_(path + "/" + i.name, uidRange, inodesSeen);
|
canonicalisePathMetaData_(i.path().string(), uidRange, inodesSeen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,10 +120,10 @@ Path canonPath(PathView path, bool resolveSymlinks)
|
||||||
|
|
||||||
Path dirOf(const PathView path)
|
Path dirOf(const PathView path)
|
||||||
{
|
{
|
||||||
Path::size_type pos = path.rfind('/');
|
Path::size_type pos = NativePathTrait::rfindPathSep(path);
|
||||||
if (pos == path.npos)
|
if (pos == path.npos)
|
||||||
return ".";
|
return ".";
|
||||||
return pos == 0 ? "/" : Path(path, 0, pos);
|
return fs::path{path}.parent_path().string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,72 +217,34 @@ bool pathAccessible(const Path & path)
|
||||||
|
|
||||||
Path readLink(const Path & path)
|
Path readLink(const Path & path)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
std::vector<char> buf;
|
return fs::read_symlink(path).string();
|
||||||
for (ssize_t bufSize = PATH_MAX/4; true; bufSize += bufSize/2) {
|
|
||||||
buf.resize(bufSize);
|
|
||||||
ssize_t rlSize = readlink(path.c_str(), buf.data(), bufSize);
|
|
||||||
if (rlSize == -1)
|
|
||||||
if (errno == EINVAL)
|
|
||||||
throw Error("'%1%' is not a symlink", path);
|
|
||||||
else
|
|
||||||
throw SysError("reading symbolic link '%1%'", path);
|
|
||||||
else if (rlSize < bufSize)
|
|
||||||
return std::string(buf.data(), rlSize);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// TODO modern Windows does in fact support symlinks
|
|
||||||
throw UnimplementedError("reading symbolic link '%1%'", path);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isLink(const Path & path)
|
bool isLink(const Path & path)
|
||||||
{
|
{
|
||||||
return getFileType(path) == DT_LNK;
|
return getFileType(path) == fs::file_type::symlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DirEntries readDirectory(DIR *dir, const Path & path)
|
std::vector<std::filesystem::directory_entry> readDirectory(const Path & path)
|
||||||
{
|
{
|
||||||
DirEntries entries;
|
std::vector<std::filesystem::directory_entry> entries;
|
||||||
entries.reserve(64);
|
entries.reserve(64);
|
||||||
|
|
||||||
struct dirent * dirent;
|
for (auto & entry : fs::directory_iterator{path}) {
|
||||||
while (errno = 0, dirent = readdir(dir)) { /* sic */
|
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
std::string name = dirent->d_name;
|
entries.push_back(std::move(entry));
|
||||||
if (name == "." || name == "..") continue;
|
|
||||||
entries.emplace_back(name, dirent->d_ino,
|
|
||||||
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
|
|
||||||
dirent->d_type
|
|
||||||
#else
|
|
||||||
DT_UNKNOWN
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (errno) throw SysError("reading directory '%1%'", path);
|
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntries readDirectory(const Path & path)
|
|
||||||
|
fs::file_type getFileType(const Path & path)
|
||||||
{
|
{
|
||||||
AutoCloseDir dir(opendir(path.c_str()));
|
return fs::symlink_status(path).type();
|
||||||
if (!dir) throw SysError("opening directory '%1%'", path);
|
|
||||||
|
|
||||||
return readDirectory(dir.get(), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char getFileType(const Path & path)
|
|
||||||
{
|
|
||||||
struct stat st = lstat(path);
|
|
||||||
if (S_ISDIR(st.st_mode)) return DT_DIR;
|
|
||||||
if (S_ISLNK(st.st_mode)) return DT_LNK;
|
|
||||||
if (S_ISREG(st.st_mode)) return DT_REG;
|
|
||||||
return DT_UNKNOWN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,8 +394,15 @@ static void _deletePath(Descriptor parentfd, const Path & path, uint64_t & bytes
|
||||||
AutoCloseDir dir(fdopendir(fd));
|
AutoCloseDir dir(fdopendir(fd));
|
||||||
if (!dir)
|
if (!dir)
|
||||||
throw SysError("opening directory '%1%'", path);
|
throw SysError("opening directory '%1%'", path);
|
||||||
for (auto & i : readDirectory(dir.get(), path))
|
|
||||||
_deletePath(dirfd(dir.get()), path + "/" + i.name, bytesFreed);
|
struct dirent * dirent;
|
||||||
|
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
|
||||||
|
checkInterrupt();
|
||||||
|
std::string childName = dirent->d_name;
|
||||||
|
if (childName == "." || childName == "..") continue;
|
||||||
|
_deletePath(dirfd(dir.get()), path + "/" + childName, bytesFreed);
|
||||||
|
}
|
||||||
|
if (errno) throw SysError("reading directory '%1%'", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
|
int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
|
||||||
|
@ -611,13 +580,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
|
||||||
|
|
||||||
void createSymlink(const Path & target, const Path & link)
|
void createSymlink(const Path & target, const Path & link)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
fs::create_symlink(target, link);
|
||||||
if (symlink(target.c_str(), link.c_str()))
|
|
||||||
throw SysError("creating symlink from '%1%' to '%2%'", link, target);
|
|
||||||
#else
|
|
||||||
// TODO modern Windows does in fact support symlinks
|
|
||||||
throw UnimplementedError("createSymlink");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void replaceSymlink(const Path & target, const Path & link)
|
void replaceSymlink(const Path & target, const Path & link)
|
||||||
|
@ -627,8 +590,8 @@ void replaceSymlink(const Path & target, const Path & link)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
createSymlink(target, tmp);
|
createSymlink(target, tmp);
|
||||||
} catch (SysError & e) {
|
} catch (fs::filesystem_error & e) {
|
||||||
if (e.errNo == EEXIST) continue;
|
if (e.code() == std::errc::file_exists) continue;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,6 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
|
|
||||||
#define DT_UNKNOWN 0
|
|
||||||
#define DT_REG 1
|
|
||||||
#define DT_LNK 2
|
|
||||||
#define DT_DIR 3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Polyfill for MinGW
|
* Polyfill for MinGW
|
||||||
*
|
*
|
||||||
|
@ -129,23 +122,9 @@ bool isLink(const Path & path);
|
||||||
* Read the contents of a directory. The entries `.` and `..` are
|
* Read the contents of a directory. The entries `.` and `..` are
|
||||||
* removed.
|
* removed.
|
||||||
*/
|
*/
|
||||||
struct DirEntry
|
std::vector<std::filesystem::directory_entry> readDirectory(const Path & path);
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
ino_t ino;
|
|
||||||
/**
|
|
||||||
* one of DT_*
|
|
||||||
*/
|
|
||||||
unsigned char type;
|
|
||||||
DirEntry(std::string name, ino_t ino, unsigned char type)
|
|
||||||
: name(std::move(name)), ino(ino), type(type) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<DirEntry> DirEntries;
|
std::filesystem::file_type getFileType(const Path & path);
|
||||||
|
|
||||||
DirEntries readDirectory(const Path & path);
|
|
||||||
|
|
||||||
unsigned char getFileType(const Path & path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the contents of a file into a string.
|
* Read the contents of a file into a string.
|
||||||
|
|
|
@ -47,26 +47,26 @@ std::map<std::string, std::string> getCgroups(const Path & cgroupFile)
|
||||||
return cgroups;
|
return cgroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CgroupStats destroyCgroup(const Path & cgroup, bool returnStats)
|
static CgroupStats destroyCgroup(const std::filesystem::path & cgroup, bool returnStats)
|
||||||
{
|
{
|
||||||
if (!pathExists(cgroup)) return {};
|
if (!pathExists(cgroup)) return {};
|
||||||
|
|
||||||
auto procsFile = cgroup + "/cgroup.procs";
|
auto procsFile = cgroup / "cgroup.procs";
|
||||||
|
|
||||||
if (!pathExists(procsFile))
|
if (!pathExists(procsFile))
|
||||||
throw Error("'%s' is not a cgroup", cgroup);
|
throw Error("'%s' is not a cgroup", cgroup);
|
||||||
|
|
||||||
/* Use the fast way to kill every process in a cgroup, if
|
/* Use the fast way to kill every process in a cgroup, if
|
||||||
available. */
|
available. */
|
||||||
auto killFile = cgroup + "/cgroup.kill";
|
auto killFile = cgroup / "cgroup.kill";
|
||||||
if (pathExists(killFile))
|
if (pathExists(killFile))
|
||||||
writeFile(killFile, "1");
|
writeFile(killFile, "1");
|
||||||
|
|
||||||
/* Otherwise, manually kill every process in the subcgroups and
|
/* Otherwise, manually kill every process in the subcgroups and
|
||||||
this cgroup. */
|
this cgroup. */
|
||||||
for (auto & entry : readDirectory(cgroup)) {
|
for (auto & entry : readDirectory(cgroup)) {
|
||||||
if (entry.type != DT_DIR) continue;
|
if (entry.symlink_status().type() != std::filesystem::file_type::directory) continue;
|
||||||
destroyCgroup(cgroup + "/" + entry.name, false);
|
destroyCgroup(cgroup / entry.path().filename(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int round = 1;
|
int round = 1;
|
||||||
|
@ -111,7 +111,7 @@ static CgroupStats destroyCgroup(const Path & cgroup, bool returnStats)
|
||||||
CgroupStats stats;
|
CgroupStats stats;
|
||||||
|
|
||||||
if (returnStats) {
|
if (returnStats) {
|
||||||
auto cpustatPath = cgroup + "/cpu.stat";
|
auto cpustatPath = cgroup / "cpu.stat";
|
||||||
|
|
||||||
if (pathExists(cpustatPath)) {
|
if (pathExists(cpustatPath)) {
|
||||||
for (auto & line : tokenizeString<std::vector<std::string>>(readFile(cpustatPath), "\n")) {
|
for (auto & line : tokenizeString<std::vector<std::string>>(readFile(cpustatPath), "\n")) {
|
||||||
|
|
|
@ -133,15 +133,32 @@ SourceAccessor::DirEntries PosixSourceAccessor::readDirectory(const CanonPath &
|
||||||
assertNoSymlinks(path);
|
assertNoSymlinks(path);
|
||||||
DirEntries res;
|
DirEntries res;
|
||||||
for (auto & entry : nix::readDirectory(makeAbsPath(path).string())) {
|
for (auto & entry : nix::readDirectory(makeAbsPath(path).string())) {
|
||||||
std::optional<Type> type;
|
auto type = [&]() -> std::optional<Type> {
|
||||||
switch (entry.type) {
|
std::filesystem::file_type nativeType;
|
||||||
case DT_REG: type = Type::tRegular; break;
|
try {
|
||||||
#ifndef _WIN32
|
nativeType = entry.symlink_status().type();
|
||||||
case DT_LNK: type = Type::tSymlink; break;
|
} catch (std::filesystem::filesystem_error & e) {
|
||||||
#endif
|
// We cannot always stat the child. (Ideally there is no
|
||||||
case DT_DIR: type = Type::tDirectory; break;
|
// stat because the native directory entry has the type
|
||||||
|
// already, but this isn't always the case.)
|
||||||
|
if (e.code() == std::errc::permission_denied || e.code() == std::errc::operation_not_permitted)
|
||||||
|
return std::nullopt;
|
||||||
|
else throw;
|
||||||
}
|
}
|
||||||
res.emplace(entry.name, type);
|
|
||||||
|
// cannot exhaustively enumerate because implementation-specific
|
||||||
|
// additional file types are allowed.
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
|
switch (nativeType) {
|
||||||
|
case std::filesystem::file_type::regular: return Type::tRegular; break;
|
||||||
|
case std::filesystem::file_type::symlink: return Type::tSymlink; break;
|
||||||
|
case std::filesystem::file_type::directory: return Type::tDirectory; break;
|
||||||
|
default: return tMisc;
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
}();
|
||||||
|
res.emplace(entry.path().filename().string(), type);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ void closeMostFDs(const std::set<int> & exceptions)
|
||||||
#if __linux__
|
#if __linux__
|
||||||
try {
|
try {
|
||||||
for (auto & s : readDirectory("/proc/self/fd")) {
|
for (auto & s : readDirectory("/proc/self/fd")) {
|
||||||
auto fd = std::stoi(s.name);
|
auto fd = std::stoi(s.path().filename());
|
||||||
if (!exceptions.count(fd)) {
|
if (!exceptions.count(fd)) {
|
||||||
debug("closing leaked FD %d", fd);
|
debug("closing leaked FD %d", fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -133,6 +133,7 @@ void closeMostFDs(const std::set<int> & exceptions)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} catch (SysError &) {
|
} catch (SysError &) {
|
||||||
|
} catch (std::filesystem::filesystem_error &) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -30,15 +30,15 @@ void removeOldGenerations(std::string dir)
|
||||||
for (auto & i : readDirectory(dir)) {
|
for (auto & i : readDirectory(dir)) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
auto path = dir + "/" + i.name;
|
auto path = i.path().string();
|
||||||
auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type;
|
auto type = i.symlink_status().type();
|
||||||
|
|
||||||
if (type == DT_LNK && canWrite) {
|
if (type == std::filesystem::file_type::symlink && canWrite) {
|
||||||
std::string link;
|
std::string link;
|
||||||
try {
|
try {
|
||||||
link = readLink(path);
|
link = readLink(path);
|
||||||
} catch (SysError & e) {
|
} catch (std::filesystem::filesystem_error & e) {
|
||||||
if (e.errNo == ENOENT) continue;
|
if (e.code() == std::errc::no_such_file_or_directory) continue;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
if (link.find("link") != std::string::npos) {
|
if (link.find("link") != std::string::npos) {
|
||||||
|
@ -49,7 +49,7 @@ void removeOldGenerations(std::string dir)
|
||||||
} else
|
} else
|
||||||
deleteOldGenerations(path, dryRun);
|
deleteOldGenerations(path, dryRun);
|
||||||
}
|
}
|
||||||
} else if (type == DT_DIR) {
|
} else if (type == std::filesystem::file_type::directory) {
|
||||||
removeOldGenerations(path);
|
removeOldGenerations(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,8 @@ struct CmdConfigCheck : StoreCommand
|
||||||
if (profileDir.find("/profiles/") == std::string::npos)
|
if (profileDir.find("/profiles/") == std::string::npos)
|
||||||
dirs.insert(dir);
|
dirs.insert(dir);
|
||||||
}
|
}
|
||||||
} catch (SystemError &) {}
|
} catch (SystemError &) {
|
||||||
|
} catch (std::filesystem::filesystem_error &) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dirs.empty()) {
|
if (!dirs.empty()) {
|
||||||
|
|
|
@ -867,8 +867,8 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||||
createDirs(to);
|
createDirs(to);
|
||||||
|
|
||||||
for (auto & entry : readDirectory(from)) {
|
for (auto & entry : readDirectory(from)) {
|
||||||
auto from2 = from + "/" + entry.name;
|
auto from2 = entry.path().string();
|
||||||
auto to2 = to + "/" + entry.name;
|
auto to2 = to + "/" + entry.path().filename().string();
|
||||||
auto st = lstat(from2);
|
auto st = lstat(from2);
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
copyDir(from2, to2);
|
copyDir(from2, to2);
|
||||||
|
|
|
@ -117,7 +117,7 @@ std::tuple<StorePath, Hash> prefetchFile(
|
||||||
that as the top-level. */
|
that as the top-level. */
|
||||||
auto entries = readDirectory(unpacked);
|
auto entries = readDirectory(unpacked);
|
||||||
if (entries.size() == 1)
|
if (entries.size() == 1)
|
||||||
tmpFile = unpacked + "/" + entries[0].name;
|
tmpFile = entries[0].path().string();
|
||||||
else
|
else
|
||||||
tmpFile = unpacked;
|
tmpFile = unpacked;
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,8 +249,8 @@ void chrootHelper(int argc, char * * argv)
|
||||||
throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir);
|
throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir);
|
||||||
|
|
||||||
for (auto entry : readDirectory("/")) {
|
for (auto entry : readDirectory("/")) {
|
||||||
auto src = "/" + entry.name;
|
auto src = entry.path().string();
|
||||||
Path dst = tmpDir + "/" + entry.name;
|
Path dst = tmpDir + "/" + entry.path().filename().string();
|
||||||
if (pathExists(dst)) continue;
|
if (pathExists(dst)) continue;
|
||||||
auto st = lstat(src);
|
auto st = lstat(src);
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
|
Loading…
Reference in a new issue