From 4bcc9fc0bb7316d08860ed018fe5da764300d4e2 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Mon, 3 Mar 2025 20:48:59 +0100 Subject: [PATCH] libstore: use new indexer in NarAccessor Change-Id: Id8f33d19aa33d6ff2ccad4469b052f8834b3547f --- lix/libstore/nar-accessor.cc | 163 +++++++++-------------------------- 1 file changed, 40 insertions(+), 123 deletions(-) diff --git a/lix/libstore/nar-accessor.cc b/lix/libstore/nar-accessor.cc index 3aaa4f761..4eacaa05b 100644 --- a/lix/libstore/nar-accessor.cc +++ b/lix/libstore/nar-accessor.cc @@ -7,140 +7,46 @@ #include #include +#include namespace nix { -struct NarMember -{ - FSAccessor::Type type = FSAccessor::Type::tMissing; - - 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 = {}; - - /* If this is a directory, all the children of the directory. */ - std::map children = {}; -}; - struct NarAccessor : public FSAccessor { std::optional nar; - + nar_index::Entry root; GetNarBytes getNarBytes; - NarMember root; - - struct NarSource : Source - { - Source & source; - uint64_t pos = 0; - - NarSource(Source & source) : source(source) {} - - size_t read(char * data, size_t len) override - { - auto n = source.read(data, len); - pos += n; - return n; - } - }; - - struct NarIndexer : NARParseVisitor - { - NarAccessor & acc; - NarSource & source; - - NarMember * parent; - - public: - NarIndexer(NarAccessor & acc, NarSource & source, NarMember & parent) - : acc(acc), source(source), parent(&parent) - { } - - NarMember & createMember(const std::string & name, NarMember member) - { - if (parent->type == FSAccessor::Type::tMissing) { - *parent = std::move(member); - return *parent; - } else { - return parent->children.emplace(name, std::move(member)).first->second; - } - } - - box_ptr createDirectory(const std::string & name) override - { - auto & dir = createMember(name, {FSAccessor::Type::tDirectory, false, 0, 0}); - return make_box_ptr(acc, source, dir); - } - - box_ptr createRegularFile(const std::string & name, uint64_t size, bool executable) override - { - auto & memb = createMember(name, {FSAccessor::Type::tRegular, false, 0, 0}); - - assert(size <= std::numeric_limits::max()); - memb.size = (uint64_t) size; - memb.start = source.pos; - memb.isExecutable = executable; - - struct IgnoringFileHandle : FileHandle - { - void close() override {} - void receiveContents(std::string_view data) override {} - }; - - return make_box_ptr(); - } - - void createSymlink(const std::string & name, const std::string & target) override - { - createMember(name, - NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); - } - }; - NarAccessor(std::string && _nar) : nar(_nar) { StringSource source(*nar); - NarSource posSource(source); - NarIndexer indexer(*this, posSource, root); - parseDump(indexer, posSource); + root = nar_index::create(source); } - NarAccessor(Source & source) - { - NarSource posSource(source); - NarIndexer indexer(*this, posSource, root); - parseDump(indexer, posSource); - } + NarAccessor(Source & source) : root(nar_index::create(source)) {} NarAccessor(const std::string & listing, GetNarBytes getNarBytes) : getNarBytes(getNarBytes) { + using namespace nar_index; using json = nlohmann::json; - std::function recurse; + std::function recurse; - recurse = [&](NarMember & member, json & v) { + recurse = [&](Entry & member, json & v) { std::string type = v["type"]; if (type == "directory") { - member.type = FSAccessor::Type::tDirectory; + Directory dir; for (auto i = v["entries"].begin(); i != v["entries"].end(); ++i) { std::string name = i.key(); - recurse(member.children[name], i.value()); + recurse(dir.contents[name], i.value()); } + member = std::move(dir); } else if (type == "regular") { - member.type = FSAccessor::Type::tRegular; - member.size = v["size"]; - member.isExecutable = v.value("executable", false); - member.start = v["narOffset"]; + member = File{v.value("executable", false), v["narOffset"], v["size"]}; } else if (type == "symlink") { - member.type = FSAccessor::Type::tSymlink; - member.target = v.value("target", ""); + member = Symlink{v.value("target", "")}; } else return; }; @@ -148,14 +54,15 @@ struct NarAccessor : public FSAccessor recurse(root, v); } - NarMember * find(const Path & path) + nar_index::Entry * find(const Path & path) { - NarMember * current = &root; + nar_index::Entry * current = &root; auto end = path.end(); for (auto it = path.begin(); it != end; ) { // because it != end, the remaining component is non-empty so we need // a directory - if (current->type != FSAccessor::Type::tDirectory) return nullptr; + auto dir = std::get_if(current); + if (!dir) return nullptr; // skip slash (canonPath above ensures that this is always a slash) assert(*it == '/'); @@ -163,8 +70,8 @@ struct NarAccessor : public FSAccessor // lookup current component auto next = std::find(it, end, '/'); - auto child = current->children.find(std::string(it, next)); - if (child == current->children.end()) return nullptr; + auto child = dir->contents.find(std::string(it, next)); + if (child == dir->contents.end()) return nullptr; current = &child->second; it = next; @@ -173,7 +80,7 @@ struct NarAccessor : public FSAccessor return current; } - NarMember & get(const Path & path) { + nar_index::Entry & get(const Path & path) { auto result = find(path); if (result == nullptr) throw Error("NAR file does not contain path '%1%'", path); @@ -185,18 +92,26 @@ struct NarAccessor : public FSAccessor auto i = find(path); if (i == nullptr) return {FSAccessor::Type::tMissing, 0, false}; - return {i->type, i->size, i->isExecutable, i->start}; + auto handlers = overloaded{ + [](const nar_index::File & f) { + return Stat{tRegular, f.size, f.executable, f.offset}; + }, + [](const nar_index::Symlink &) { return Stat{tSymlink}; }, + [](const nar_index::Directory &) { return Stat{tDirectory}; }, + }; + return std::visit(handlers, *i); } StringSet readDirectory(const Path & path) override { - auto i = get(path); + auto & i = get(path); + auto dir = std::get_if(&i); - if (i.type != FSAccessor::Type::tDirectory) + if (!dir) throw Error("path '%1%' inside NAR file is not a directory", path); StringSet res; - for (auto & child : i.children) + for (auto & child : dir->contents) res.insert(child.first); return res; @@ -204,22 +119,24 @@ struct NarAccessor : public FSAccessor std::string readFile(const Path & path, bool requireValidPath = true) override { - auto i = get(path); - if (i.type != FSAccessor::Type::tRegular) + auto & i = get(path); + auto file = std::get_if(&i); + if (!file) 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(file->offset, file->size); assert(nar); - return std::string(*nar, i.start, i.size); + return std::string(*nar, file->offset, file->size); } std::string readLink(const Path & path) override { - auto i = get(path); - if (i.type != FSAccessor::Type::tSymlink) + auto & i = get(path); + auto link = std::get_if(&i); + if (!link) throw Error("path '%1%' inside NAR file is not a symlink", path); - return i.target; + return link->target; } };