Use std::filesystem functions in more places

This makes for shorter and more portable code.

The only tricky part is catching exceptions: I just searched for near by
`catch (Error &)` or `catch (SysError &)` and adjusted them to `catch
(std::filesystem::filesystem_error &)` according to my human judgement.

Good for windows portability; will help @siddhantk232 with his GSOC
project.
This commit is contained in:
John Ericson 2024-05-07 00:14:49 -04:00
parent b4950404ba
commit c371070580
14 changed files with 61 additions and 99 deletions

View file

@ -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

View file

@ -264,6 +264,7 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
completions.insert(prev + dir + "/" + entry.name); completions.insert(prev + dir + "/" + entry.name);
} }
} 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. */

View file

@ -21,8 +21,8 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
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;
} }

View file

@ -348,8 +348,8 @@ void initPlugins()
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(pluginFile + "/" + ent.name);
} 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);
} }

View file

@ -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;
} }
} }

View file

@ -203,7 +203,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 +217,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(path + "/" + i.name, i.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 +247,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);
@ -268,8 +268,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

View file

@ -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);

View file

@ -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,36 @@ 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) DirEntries readDirectory(const Path & path)
{ {
DirEntries entries; DirEntries 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.emplace_back(
if (name == "." || name == "..") continue; entry.path().filename().string(),
entries.emplace_back(name, dirent->d_ino, entry.symlink_status().type());
#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 +396,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 +582,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 +592,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;
} }

View file

@ -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
* *
@ -132,20 +125,16 @@ bool isLink(const Path & path);
struct DirEntry struct DirEntry
{ {
std::string name; std::string name;
ino_t ino; std::filesystem::file_type type;
/** DirEntry(std::string name, std::filesystem::file_type type)
* one of DT_* : name(std::move(name)), type(type) { }
*/
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; typedef std::vector<DirEntry> DirEntries;
DirEntries readDirectory(const Path & path); DirEntries readDirectory(const Path & path);
unsigned char getFileType(const Path & path); std::filesystem::file_type getFileType(const Path & path);
/** /**
* Read the contents of a file into a string. * Read the contents of a file into a string.

View file

@ -65,7 +65,7 @@ static CgroupStats destroyCgroup(const Path & cgroup, bool returnStats)
/* 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.type != std::filesystem::file_type::directory) continue;
destroyCgroup(cgroup + "/" + entry.name, false); destroyCgroup(cgroup + "/" + entry.name, false);
} }

View file

@ -134,13 +134,17 @@ SourceAccessor::DirEntries PosixSourceAccessor::readDirectory(const CanonPath &
DirEntries res; DirEntries res;
for (auto & entry : nix::readDirectory(makeAbsPath(path).string())) { for (auto & entry : nix::readDirectory(makeAbsPath(path).string())) {
std::optional<Type> type; std::optional<Type> type;
// cannot exhaustively enumerate because implementation-specific
// additional file types are allowed.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch (entry.type) { switch (entry.type) {
case DT_REG: type = Type::tRegular; break; case std::filesystem::file_type::regular: type = Type::tRegular; break;
#ifndef _WIN32 case std::filesystem::file_type::symlink: type = Type::tSymlink; break;
case DT_LNK: type = Type::tSymlink; break; case std::filesystem::file_type::directory: type = Type::tDirectory; break;
#endif default: type = tMisc;
case DT_DIR: type = Type::tDirectory; break;
} }
#pragma GCC diagnostic pop
res.emplace(entry.name, type); res.emplace(entry.name, type);
} }
return res; return res;

View file

@ -133,6 +133,7 @@ void closeMostFDs(const std::set<int> & exceptions)
} }
return; return;
} catch (SysError &) { } catch (SysError &) {
} catch (std::filesystem::filesystem_error &) {
} }
#endif #endif

View file

@ -31,14 +31,14 @@ void removeOldGenerations(std::string dir)
checkInterrupt(); checkInterrupt();
auto path = dir + "/" + i.name; auto path = dir + "/" + i.name;
auto type = i.type == DT_UNKNOWN ? getFileType(path) : i.type; auto type = i.type == std::filesystem::file_type::unknown ? getFileType(path) : i.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);
} }
} }

View file

@ -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()) {