1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 19:01:16 +02:00

Remove FSAccessor::Type::tMissing

Instead stat() now returns std::nullopt to denote that the file
doesn't exist.
This commit is contained in:
Eelco Dolstra 2023-11-01 14:36:40 +01:00
parent e3febfcd53
commit b2ac6fc040
10 changed files with 77 additions and 74 deletions

View file

@ -208,7 +208,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
std::string buildIdDir = "/lib/debug/.build-id"; std::string buildIdDir = "/lib/debug/.build-id";
if (narAccessor->stat(buildIdDir).type == FSAccessor::tDirectory) { if (auto st = narAccessor->stat(buildIdDir); st && st->type == FSAccessor::tDirectory) {
ThreadPool threadPool(25); ThreadPool threadPool(25);
@ -234,14 +234,14 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
for (auto & s1 : narAccessor->readDirectory(buildIdDir)) { for (auto & s1 : narAccessor->readDirectory(buildIdDir)) {
auto dir = buildIdDir + "/" + s1; auto dir = buildIdDir + "/" + s1;
if (narAccessor->stat(dir).type != FSAccessor::tDirectory if (auto st = narAccessor->stat(dir); !st || st->type != FSAccessor::tDirectory
|| !std::regex_match(s1, regex1)) || !std::regex_match(s1, regex1))
continue; continue;
for (auto & s2 : narAccessor->readDirectory(dir)) { for (auto & s2 : narAccessor->readDirectory(dir)) {
auto debugPath = dir + "/" + s2; auto debugPath = dir + "/" + s2;
if (narAccessor->stat(debugPath).type != FSAccessor::tRegular if (auto st = narAccessor->stat(debugPath); !st || st->type != FSAccessor::tRegular
|| !std::regex_match(s2, regex2)) || !std::regex_match(s2, regex2))
continue; continue;

View file

@ -3,6 +3,8 @@
#include "types.hh" #include "types.hh"
#include <optional>
namespace nix { namespace nix {
/** /**
@ -12,28 +14,29 @@ namespace nix {
class FSAccessor class FSAccessor
{ {
public: public:
enum Type { tMissing, tRegular, tSymlink, tDirectory }; enum Type { tRegular, tSymlink, tDirectory };
struct Stat struct Stat
{ {
Type type = tMissing; Type type;
/** /**
* regular files only * For regular files only: the size of the file.
*/ */
uint64_t fileSize = 0; uint64_t fileSize = 0;
/** /**
* regular files only * For regular files only: whether this is an executable.
*/ */
bool isExecutable = false; // regular files only bool isExecutable = false;
/** /**
* regular files only * For regular files only: the position of the contents of this
* file in the NAR.
*/ */
uint64_t narOffset = 0; // regular files only uint64_t narOffset = 0;
}; };
virtual ~FSAccessor() { } virtual ~FSAccessor() { }
virtual Stat stat(const Path & path) = 0; virtual std::optional<Stat> stat(const Path & path) = 0;
virtual StringSet readDirectory(const Path & path) = 0; virtual StringSet readDirectory(const Path & path) = 0;

View file

@ -27,25 +27,25 @@ struct LocalStoreAccessor : public FSAccessor
return store->getRealStoreDir() + std::string(path, store->storeDir.size()); return store->getRealStoreDir() + std::string(path, store->storeDir.size());
} }
FSAccessor::Stat stat(const Path & path) override std::optional<FSAccessor::Stat> stat(const Path & path) override
{ {
auto realPath = toRealPath(path); auto realPath = toRealPath(path);
struct stat st; struct stat st;
if (lstat(realPath.c_str(), &st)) { if (lstat(realPath.c_str(), &st)) {
if (errno == ENOENT || errno == ENOTDIR) return {Type::tMissing, 0, false}; if (errno == ENOENT || errno == ENOTDIR) return std::nullopt;
throw SysError("getting status of '%1%'", path); throw SysError("getting status of '%1%'", path);
} }
if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode)) if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode))
throw Error("file '%1%' has unsupported type", path); throw Error("file '%1%' has unsupported type", path);
return { return {{
S_ISREG(st.st_mode) ? Type::tRegular : S_ISREG(st.st_mode) ? Type::tRegular :
S_ISLNK(st.st_mode) ? Type::tSymlink : S_ISLNK(st.st_mode) ? Type::tSymlink :
Type::tDirectory, Type::tDirectory,
S_ISREG(st.st_mode) ? (uint64_t) st.st_size : 0, S_ISREG(st.st_mode) ? (uint64_t) st.st_size : 0,
S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}; S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}};
} }
StringSet readDirectory(const Path & path) override StringSet readDirectory(const Path & path) override

View file

@ -11,13 +11,7 @@ namespace nix {
struct NarMember struct NarMember
{ {
FSAccessor::Type type = FSAccessor::Type::tMissing; FSAccessor::Stat stat;
bool isExecutable = false;
/* If this is a regular file, position of the contents of this
file in the NAR. */
uint64_t start = 0, size = 0;
std::string target; std::string target;
@ -57,7 +51,7 @@ struct NarAccessor : public FSAccessor
acc.root = std::move(member); acc.root = std::move(member);
parents.push(&acc.root); parents.push(&acc.root);
} else { } else {
if (parents.top()->type != FSAccessor::Type::tDirectory) if (parents.top()->stat.type != FSAccessor::Type::tDirectory)
throw Error("NAR file missing parent directory of path '%s'", path); throw Error("NAR file missing parent directory of path '%s'", path);
auto result = parents.top()->children.emplace(baseNameOf(path), std::move(member)); auto result = parents.top()->children.emplace(baseNameOf(path), std::move(member));
parents.push(&result.first->second); parents.push(&result.first->second);
@ -79,14 +73,15 @@ struct NarAccessor : public FSAccessor
void isExecutable() override void isExecutable() override
{ {
parents.top()->isExecutable = true; parents.top()->stat.isExecutable = true;
} }
void preallocateContents(uint64_t size) override void preallocateContents(uint64_t size) override
{ {
assert(size <= std::numeric_limits<uint64_t>::max()); assert(size <= std::numeric_limits<uint64_t>::max());
parents.top()->size = (uint64_t) size; auto & st = parents.top()->stat;
parents.top()->start = pos; st.fileSize = (uint64_t) size;
st.narOffset = pos;
} }
void receiveContents(std::string_view data) override void receiveContents(std::string_view data) override
@ -95,7 +90,9 @@ struct NarAccessor : public FSAccessor
void createSymlink(const Path & path, const std::string & target) override void createSymlink(const Path & path, const std::string & target) override
{ {
createMember(path, createMember(path,
NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); NarMember{
.stat = {.type = FSAccessor::Type::tSymlink},
.target = target});
} }
size_t read(char * data, size_t len) override size_t read(char * data, size_t len) override
@ -130,18 +127,20 @@ struct NarAccessor : public FSAccessor
std::string type = v["type"]; std::string type = v["type"];
if (type == "directory") { if (type == "directory") {
member.type = FSAccessor::Type::tDirectory; member.stat = {.type = FSAccessor::Type::tDirectory};
for (auto i = v["entries"].begin(); i != v["entries"].end(); ++i) { for (auto i = v["entries"].begin(); i != v["entries"].end(); ++i) {
std::string name = i.key(); std::string name = i.key();
recurse(member.children[name], i.value()); recurse(member.children[name], i.value());
} }
} else if (type == "regular") { } else if (type == "regular") {
member.type = FSAccessor::Type::tRegular; member.stat = {
member.size = v["size"]; .type = FSAccessor::Type::tRegular,
member.isExecutable = v.value("executable", false); .fileSize = v["size"],
member.start = v["narOffset"]; .isExecutable = v.value("executable", false),
.narOffset = v["narOffset"]
};
} else if (type == "symlink") { } else if (type == "symlink") {
member.type = FSAccessor::Type::tSymlink; member.stat = {.type = FSAccessor::Type::tSymlink};
member.target = v.value("target", ""); member.target = v.value("target", "");
} else return; } else return;
}; };
@ -158,7 +157,7 @@ struct NarAccessor : public FSAccessor
for (auto it = path.begin(); it != end; ) { for (auto it = path.begin(); it != end; ) {
// because it != end, the remaining component is non-empty so we need // because it != end, the remaining component is non-empty so we need
// a directory // a directory
if (current->type != FSAccessor::Type::tDirectory) return nullptr; if (current->stat.type != FSAccessor::Type::tDirectory) return nullptr;
// skip slash (canonPath above ensures that this is always a slash) // skip slash (canonPath above ensures that this is always a slash)
assert(*it == '/'); assert(*it == '/');
@ -183,19 +182,19 @@ struct NarAccessor : public FSAccessor
return *result; return *result;
} }
Stat stat(const Path & path) override std::optional<Stat> stat(const Path & path) override
{ {
auto i = find(path); auto i = find(path);
if (i == nullptr) if (i == nullptr)
return {FSAccessor::Type::tMissing, 0, false}; return std::nullopt;
return {i->type, i->size, i->isExecutable, i->start}; return i->stat;
} }
StringSet readDirectory(const Path & path) override StringSet readDirectory(const Path & path) override
{ {
auto i = get(path); auto i = get(path);
if (i.type != FSAccessor::Type::tDirectory) if (i.stat.type != FSAccessor::Type::tDirectory)
throw Error("path '%1%' inside NAR file is not a directory", path); throw Error("path '%1%' inside NAR file is not a directory", path);
StringSet res; StringSet res;
@ -208,19 +207,19 @@ struct NarAccessor : public FSAccessor
std::string readFile(const Path & path, bool requireValidPath = true) override std::string readFile(const Path & path, bool requireValidPath = true) override
{ {
auto i = get(path); auto i = get(path);
if (i.type != FSAccessor::Type::tRegular) if (i.stat.type != FSAccessor::Type::tRegular)
throw Error("path '%1%' inside NAR file is not a regular file", path); throw Error("path '%1%' inside NAR file is not a regular file", path);
if (getNarBytes) return getNarBytes(i.start, i.size); if (getNarBytes) return getNarBytes(i.stat.narOffset, i.stat.fileSize);
assert(nar); assert(nar);
return std::string(*nar, i.start, i.size); return std::string(*nar, i.stat.narOffset, i.stat.fileSize);
} }
std::string readLink(const Path & path) override std::string readLink(const Path & path) override
{ {
auto i = get(path); auto i = get(path);
if (i.type != FSAccessor::Type::tSymlink) if (i.stat.type != FSAccessor::Type::tSymlink)
throw Error("path '%1%' inside NAR file is not a symlink", path); throw Error("path '%1%' inside NAR file is not a symlink", path);
return i.target; return i.target;
} }
@ -246,17 +245,19 @@ using nlohmann::json;
json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse) json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse)
{ {
auto st = accessor->stat(path); auto st = accessor->stat(path);
if (!st)
throw Error("path '%s' does not exist in NAR", path);
json obj = json::object(); json obj = json::object();
switch (st.type) { switch (st->type) {
case FSAccessor::Type::tRegular: case FSAccessor::Type::tRegular:
obj["type"] = "regular"; obj["type"] = "regular";
obj["size"] = st.fileSize; obj["size"] = st->fileSize;
if (st.isExecutable) if (st->isExecutable)
obj["executable"] = true; obj["executable"] = true;
if (st.narOffset) if (st->narOffset)
obj["narOffset"] = st.narOffset; obj["narOffset"] = st->narOffset;
break; break;
case FSAccessor::Type::tDirectory: case FSAccessor::Type::tDirectory:
obj["type"] = "directory"; obj["type"] = "directory";
@ -275,9 +276,6 @@ json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse)
obj["type"] = "symlink"; obj["type"] = "symlink";
obj["target"] = accessor->readLink(path); obj["target"] = accessor->readLink(path);
break; break;
case FSAccessor::Type::tMissing:
default:
throw Error("path '%s' does not exist in NAR", path);
} }
return obj; return obj;
} }

View file

@ -101,7 +101,7 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_, boo
return {addToCache(storePath.hashPart(), std::move(sink.s)), restPath}; return {addToCache(storePath.hashPart(), std::move(sink.s)), restPath};
} }
FSAccessor::Stat RemoteFSAccessor::stat(const Path & path) std::optional<FSAccessor::Stat> RemoteFSAccessor::stat(const Path & path)
{ {
auto res = fetch(path); auto res = fetch(path);
return res.first->stat(res.second); return res.first->stat(res.second);

View file

@ -28,7 +28,7 @@ public:
RemoteFSAccessor(ref<Store> store, RemoteFSAccessor(ref<Store> store,
const /* FIXME: use std::optional */ Path & cacheDir = ""); const /* FIXME: use std::optional */ Path & cacheDir = "");
Stat stat(const Path & path) override; std::optional<Stat> stat(const Path & path) override;
StringSet readDirectory(const Path & path) override; StringSet readDirectory(const Path & path) override;

View file

@ -11,13 +11,12 @@ struct MixCat : virtual Args
void cat(ref<FSAccessor> accessor) void cat(ref<FSAccessor> accessor)
{ {
auto st = accessor->stat(path); if (auto st = accessor->stat(path)) {
if (st.type == FSAccessor::Type::tMissing) if (st->type != FSAccessor::Type::tRegular)
throw Error("path '%1%' is not a regular file", path);
writeFull(STDOUT_FILENO, accessor->readFile(path));
} else
throw Error("path '%1%' does not exist", path); throw Error("path '%1%' does not exist", path);
if (st.type != FSAccessor::Type::tRegular)
throw Error("path '%1%' is not a regular file", path);
writeFull(STDOUT_FILENO, accessor->readFile(path));
} }
}; };

View file

@ -46,23 +46,25 @@ struct MixLs : virtual Args, MixJSON
auto showFile = [&](const Path & curPath, const std::string & relPath) { auto showFile = [&](const Path & curPath, const std::string & relPath) {
if (verbose) { if (verbose) {
auto st = accessor->stat(curPath); auto st = accessor->stat(curPath);
assert(st);
std::string tp = std::string tp =
st.type == FSAccessor::Type::tRegular ? st->type == FSAccessor::Type::tRegular ?
(st.isExecutable ? "-r-xr-xr-x" : "-r--r--r--") : (st->isExecutable ? "-r-xr-xr-x" : "-r--r--r--") :
st.type == FSAccessor::Type::tSymlink ? "lrwxrwxrwx" : st->type == FSAccessor::Type::tSymlink ? "lrwxrwxrwx" :
"dr-xr-xr-x"; "dr-xr-xr-x";
auto line = fmt("%s %20d %s", tp, st.fileSize, relPath); auto line = fmt("%s %20d %s", tp, st->fileSize, relPath);
if (st.type == FSAccessor::Type::tSymlink) if (st->type == FSAccessor::Type::tSymlink)
line += " -> " + accessor->readLink(curPath); line += " -> " + accessor->readLink(curPath);
logger->cout(line); logger->cout(line);
if (recursive && st.type == FSAccessor::Type::tDirectory) if (recursive && st->type == FSAccessor::Type::tDirectory)
doPath(st, curPath, relPath, false); doPath(*st, curPath, relPath, false);
} else { } else {
logger->cout(relPath); logger->cout(relPath);
if (recursive) { if (recursive) {
auto st = accessor->stat(curPath); auto st = accessor->stat(curPath);
if (st.type == FSAccessor::Type::tDirectory) assert(st);
doPath(st, curPath, relPath, false); if (st->type == FSAccessor::Type::tDirectory)
doPath(*st, curPath, relPath, false);
} }
} }
}; };
@ -79,10 +81,10 @@ struct MixLs : virtual Args, MixJSON
}; };
auto st = accessor->stat(path); auto st = accessor->stat(path);
if (st.type == FSAccessor::Type::tMissing) if (!st)
throw Error("path '%1%' does not exist", path); throw Error("path '%1%' does not exist", path);
doPath(st, path, doPath(*st, path,
st.type == FSAccessor::Type::tDirectory ? "." : std::string(baseNameOf(path)), st->type == FSAccessor::Type::tDirectory ? "." : std::string(baseNameOf(path)),
showDirectory); showDirectory);
} }

View file

@ -120,7 +120,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
unixPath.push_front(store->printStorePath(path) + "/bin"); unixPath.push_front(store->printStorePath(path) + "/bin");
auto propPath = store->printStorePath(path) + "/nix-support/propagated-user-env-packages"; auto propPath = store->printStorePath(path) + "/nix-support/propagated-user-env-packages";
if (accessor->stat(propPath).type == FSAccessor::tRegular) { if (auto st = accessor->stat(propPath); st && st->type == FSAccessor::tRegular) {
for (auto & p : tokenizeString<Paths>(readFile(propPath))) for (auto & p : tokenizeString<Paths>(readFile(propPath)))
todo.push(store->parseStorePath(p)); todo.push(store->parseStorePath(p));
} }

View file

@ -214,6 +214,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
visitPath = [&](const Path & p) { visitPath = [&](const Path & p) {
auto st = accessor->stat(p); auto st = accessor->stat(p);
assert(st);
auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1); auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1);
@ -221,13 +222,13 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE; return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
}; };
if (st.type == FSAccessor::Type::tDirectory) { if (st->type == FSAccessor::Type::tDirectory) {
auto names = accessor->readDirectory(p); auto names = accessor->readDirectory(p);
for (auto & name : names) for (auto & name : names)
visitPath(p + "/" + name); visitPath(p + "/" + name);
} }
else if (st.type == FSAccessor::Type::tRegular) { else if (st->type == FSAccessor::Type::tRegular) {
auto contents = accessor->readFile(p); auto contents = accessor->readFile(p);
for (auto & hash : hashes) { for (auto & hash : hashes) {
@ -245,7 +246,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
} }
} }
else if (st.type == FSAccessor::Type::tSymlink) { else if (st->type == FSAccessor::Type::tSymlink) {
auto target = accessor->readLink(p); auto target = accessor->readLink(p);
for (auto & hash : hashes) { for (auto & hash : hashes) {