Factor out nix::maybeLstat

This function is nice for more than `PosixSourceAccessor`. We can make a
few things simpler with it.

Note that the error logic slightly changes in some of the call sites, in
that we also count `ENOTDIR` and not just `ENOENT` as not having the
file, but that should be fine.
This commit is contained in:
John Ericson 2024-03-29 15:21:10 -04:00
parent eeecbb9c36
commit 8be347afca
5 changed files with 36 additions and 37 deletions

View file

@ -2053,13 +2053,13 @@ void LocalDerivationGoal::runChild()
i.first, i.second.source); i.first, i.second.source);
std::string path = i.first; std::string path = i.first;
struct stat st; auto optSt = maybeLstat(path.c_str());
if (lstat(path.c_str(), &st)) { if (!optSt) {
if (i.second.optional && errno == ENOENT) if (i.second.optional)
continue; continue;
throw SysError("getting attributes of path '%s", path); throw SysError("getting attributes of required path '%s", path);
} }
if (S_ISDIR(st.st_mode)) if (S_ISDIR(optSt->st_mode))
sandboxProfile += fmt("\t(subpath \"%s\")\n", path); sandboxProfile += fmt("\t(subpath \"%s\")\n", path);
else else
sandboxProfile += fmt("\t(literal \"%s\")\n", path); sandboxProfile += fmt("\t(literal \"%s\")\n", path);
@ -2271,14 +2271,12 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
continue; continue;
} }
struct stat st; auto optSt = maybeLstat(actualPath.c_str());
if (lstat(actualPath.c_str(), &st) == -1) { if (!optSt)
if (errno == ENOENT) throw BuildError(
throw BuildError( "builder for '%s' failed to produce output path for output '%s' at '%s'",
"builder for '%s' failed to produce output path for output '%s' at '%s'", worker.store.printStorePath(drvPath), outputName, actualPath);
worker.store.printStorePath(drvPath), outputName, actualPath); struct stat & st = *optSt;
throw SysError("getting attributes of path '%s'", actualPath);
}
#ifndef __CYGWIN__ #ifndef __CYGWIN__
/* Check that the output is not group or world writable, as /* Check that the output is not group or world writable, as

View file

@ -64,9 +64,9 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
continue; continue;
else if (S_ISDIR(srcSt.st_mode)) { else if (S_ISDIR(srcSt.st_mode)) {
struct stat dstSt; auto dstStOpt = maybeLstat(dstFile.c_str());
auto res = lstat(dstFile.c_str(), &dstSt); if (dstStOpt) {
if (res == 0) { auto & dstSt = *dstStOpt;
if (S_ISDIR(dstSt.st_mode)) { if (S_ISDIR(dstSt.st_mode)) {
createLinks(state, srcFile, dstFile, priority); createLinks(state, srcFile, dstFile, priority);
continue; continue;
@ -82,14 +82,13 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
createLinks(state, srcFile, dstFile, priority); createLinks(state, srcFile, dstFile, priority);
continue; continue;
} }
} else if (errno != ENOENT) }
throw SysError("getting status of '%1%'", dstFile);
} }
else { else {
struct stat dstSt; auto dstStOpt = maybeLstat(dstFile.c_str());
auto res = lstat(dstFile.c_str(), &dstSt); if (dstStOpt) {
if (res == 0) { auto & dstSt = *dstStOpt;
if (S_ISLNK(dstSt.st_mode)) { if (S_ISLNK(dstSt.st_mode)) {
auto prevPriority = state.priorities[dstFile]; auto prevPriority = state.priorities[dstFile];
if (prevPriority == priority) if (prevPriority == priority)
@ -104,8 +103,7 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
throw SysError("unlinking '%1%'", dstFile); throw SysError("unlinking '%1%'", dstFile);
} else if (S_ISDIR(dstSt.st_mode)) } else if (S_ISDIR(dstSt.st_mode))
throw Error("collision between non-directory '%1%' and directory '%2%'", srcFile, dstFile); throw Error("collision between non-directory '%1%' and directory '%2%'", srcFile, dstFile);
} else if (errno != ENOENT) }
throw SysError("getting status of '%1%'", dstFile);
} }
createSymlink(srcFile, dstFile); createSymlink(srcFile, dstFile);

View file

@ -174,15 +174,23 @@ struct stat lstat(const Path & path)
} }
std::optional<struct stat> maybeLstat(const Path & path)
{
std::optional<struct stat> st{std::in_place};
if (lstat(path.c_str(), &*st))
{
if (errno == ENOENT || errno == ENOTDIR)
st.reset();
else
throw SysError("getting status of '%s'", path);
}
return st;
}
bool pathExists(const Path & path) bool pathExists(const Path & path)
{ {
int res; return maybeLstat(path).has_value();
struct stat st;
res = lstat(path.c_str(), &st);
if (!res) return true;
if (errno != ENOENT && errno != ENOTDIR)
throw SysError("getting status of %1%", path);
return false;
} }
bool pathAccessible(const Path & path) bool pathAccessible(const Path & path)

View file

@ -84,6 +84,7 @@ bool isDirOrInDir(std::string_view path, std::string_view dir);
*/ */
struct stat stat(const Path & path); struct stat stat(const Path & path);
struct stat lstat(const Path & path); struct stat lstat(const Path & path);
std::optional<struct stat> maybeLstat(const Path & path);
/** /**
* @return true iff the given path exists. * @return true iff the given path exists.

View file

@ -97,13 +97,7 @@ std::optional<struct stat> PosixSourceAccessor::cachedLstat(const CanonPath & pa
if (i != cache->end()) return i->second; if (i != cache->end()) return i->second;
} }
std::optional<struct stat> st{std::in_place}; auto st = nix::maybeLstat(absPath.c_str());
if (::lstat(absPath.c_str(), &*st)) {
if (errno == ENOENT || errno == ENOTDIR)
st.reset();
else
throw SysError("getting status of '%s'", showPath(path));
}
auto cache(_cache.lock()); auto cache(_cache.lock());
if (cache->size() >= 16384) cache->clear(); if (cache->size() >= 16384) cache->clear();