diff options
Diffstat (limited to 'third_party/nix/src/libstore/nar-accessor.cc')
-rw-r--r-- | third_party/nix/src/libstore/nar-accessor.cc | 400 |
1 files changed, 188 insertions, 212 deletions
diff --git a/third_party/nix/src/libstore/nar-accessor.cc b/third_party/nix/src/libstore/nar-accessor.cc index b74480684f2a..f5073ad98076 100644 --- a/third_party/nix/src/libstore/nar-accessor.cc +++ b/third_party/nix/src/libstore/nar-accessor.cc @@ -1,266 +1,242 @@ #include "nar-accessor.hh" -#include "archive.hh" -#include "json.hh" - -#include <map> -#include <stack> #include <algorithm> - +#include <map> #include <nlohmann/json.hpp> +#include <stack> +#include "archive.hh" +#include "json.hh" namespace nix { -struct NarMember -{ - FSAccessor::Type type = FSAccessor::Type::tMissing; +struct NarMember { + FSAccessor::Type type = FSAccessor::Type::tMissing; - bool isExecutable = false; + bool isExecutable = false; - /* If this is a regular file, position of the contents of this - file in the NAR. */ - size_t start = 0, size = 0; + /* If this is a regular file, position of the contents of this + file in the NAR. */ + size_t start = 0, size = 0; - std::string target; + std::string target; - /* If this is a directory, all the children of the directory. */ - std::map<std::string, NarMember> children; + /* If this is a directory, all the children of the directory. */ + std::map<std::string, NarMember> children; }; -struct NarAccessor : public FSAccessor -{ - std::shared_ptr<const std::string> nar; - - GetNarBytes getNarBytes; - - NarMember root; - - struct NarIndexer : ParseSink, StringSource - { - NarAccessor & acc; +struct NarAccessor : public FSAccessor { + std::shared_ptr<const std::string> nar; - std::stack<NarMember *> parents; + GetNarBytes getNarBytes; - std::string currentStart; - bool isExec = false; + NarMember root; - NarIndexer(NarAccessor & acc, const std::string & nar) - : StringSource(nar), acc(acc) - { } + struct NarIndexer : ParseSink, StringSource { + NarAccessor& acc; - void createMember(const Path & path, NarMember member) { - size_t level = std::count(path.begin(), path.end(), '/'); - while (parents.size() > level) parents.pop(); + std::stack<NarMember*> parents; - if (parents.empty()) { - acc.root = std::move(member); - parents.push(&acc.root); - } else { - if (parents.top()->type != FSAccessor::Type::tDirectory) - throw Error("NAR file missing parent directory of path '%s'", path); - auto result = parents.top()->children.emplace(baseNameOf(path), std::move(member)); - parents.push(&result.first->second); - } - } + std::string currentStart; + bool isExec = false; - void createDirectory(const Path & path) override - { - createMember(path, {FSAccessor::Type::tDirectory, false, 0, 0}); - } + NarIndexer(NarAccessor& acc, const std::string& nar) + : StringSource(nar), acc(acc) {} - void createRegularFile(const Path & path) override - { - createMember(path, {FSAccessor::Type::tRegular, false, 0, 0}); - } + void createMember(const Path& path, NarMember member) { + size_t level = std::count(path.begin(), path.end(), '/'); + while (parents.size() > level) parents.pop(); - void isExecutable() override - { - parents.top()->isExecutable = true; - } - - void preallocateContents(unsigned long long size) override - { - currentStart = string(s, pos, 16); - assert(size <= std::numeric_limits<size_t>::max()); - parents.top()->size = (size_t)size; - parents.top()->start = pos; - } - - void receiveContents(unsigned char * data, unsigned int len) override - { - // Sanity check - if (!currentStart.empty()) { - assert(len < 16 || currentStart == string((char *) data, 16)); - currentStart.clear(); - } - } - - void createSymlink(const Path & path, const string & target) override - { - createMember(path, - NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); - } - }; + if (parents.empty()) { + acc.root = std::move(member); + parents.push(&acc.root); + } else { + if (parents.top()->type != FSAccessor::Type::tDirectory) + throw Error("NAR file missing parent directory of path '%s'", path); + auto result = parents.top()->children.emplace(baseNameOf(path), + std::move(member)); + parents.push(&result.first->second); + } + } - NarAccessor(ref<const std::string> nar) : nar(nar) - { - NarIndexer indexer(*this, *nar); - parseDump(indexer, indexer); + void createDirectory(const Path& path) override { + createMember(path, {FSAccessor::Type::tDirectory, false, 0, 0}); } - NarAccessor(const std::string & listing, GetNarBytes getNarBytes) - : getNarBytes(getNarBytes) - { - using json = nlohmann::json; - - std::function<void(NarMember &, json &)> recurse; - - recurse = [&](NarMember & member, json & v) { - std::string type = v["type"]; - - if (type == "directory") { - member.type = FSAccessor::Type::tDirectory; - for (auto i = v["entries"].begin(); i != v["entries"].end(); ++i) { - std::string name = i.key(); - recurse(member.children[name], i.value()); - } - } else if (type == "regular") { - member.type = FSAccessor::Type::tRegular; - member.size = v["size"]; - member.isExecutable = v.value("executable", false); - member.start = v["narOffset"]; - } else if (type == "symlink") { - member.type = FSAccessor::Type::tSymlink; - member.target = v.value("target", ""); - } else return; - }; - - json v = json::parse(listing); - recurse(root, v); + void createRegularFile(const Path& path) override { + createMember(path, {FSAccessor::Type::tRegular, false, 0, 0}); } - NarMember * find(const Path & path) - { - Path canon = path == "" ? "" : canonPath(path); - NarMember * 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; - - // skip slash (canonPath above ensures that this is always a slash) - assert(*it == '/'); - it += 1; - - // 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; - current = &child->second; - - it = next; - } + void isExecutable() override { parents.top()->isExecutable = true; } - return current; + void preallocateContents(unsigned long long size) override { + currentStart = string(s, pos, 16); + assert(size <= std::numeric_limits<size_t>::max()); + parents.top()->size = (size_t)size; + parents.top()->start = pos; } - NarMember & get(const Path & path) { - auto result = find(path); - if (result == nullptr) - throw Error("NAR file does not contain path '%1%'", path); - return *result; + void receiveContents(unsigned char* data, unsigned int len) override { + // Sanity check + if (!currentStart.empty()) { + assert(len < 16 || currentStart == string((char*)data, 16)); + currentStart.clear(); + } } - Stat stat(const Path & path) override - { - auto i = find(path); - if (i == nullptr) - return {FSAccessor::Type::tMissing, 0, false}; - return {i->type, i->size, i->isExecutable, i->start}; + void createSymlink(const Path& path, const string& target) override { + createMember(path, + NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); } + }; - StringSet readDirectory(const Path & path) override - { - auto i = get(path); - - if (i.type != FSAccessor::Type::tDirectory) - throw Error(format("path '%1%' inside NAR file is not a directory") % path); + NarAccessor(ref<const std::string> nar) : nar(nar) { + NarIndexer indexer(*this, *nar); + parseDump(indexer, indexer); + } - StringSet res; - for (auto & child : i.children) - res.insert(child.first); + NarAccessor(const std::string& listing, GetNarBytes getNarBytes) + : getNarBytes(getNarBytes) { + using json = nlohmann::json; - return res; - } + std::function<void(NarMember&, json&)> recurse; - std::string readFile(const Path & path) override - { - auto i = get(path); - if (i.type != FSAccessor::Type::tRegular) - throw Error(format("path '%1%' inside NAR file is not a regular file") % path); + recurse = [&](NarMember& member, json& v) { + std::string type = v["type"]; - if (getNarBytes) return getNarBytes(i.start, i.size); + if (type == "directory") { + member.type = FSAccessor::Type::tDirectory; + for (auto i = v["entries"].begin(); i != v["entries"].end(); ++i) { + std::string name = i.key(); + recurse(member.children[name], i.value()); + } + } else if (type == "regular") { + member.type = FSAccessor::Type::tRegular; + member.size = v["size"]; + member.isExecutable = v.value("executable", false); + member.start = v["narOffset"]; + } else if (type == "symlink") { + member.type = FSAccessor::Type::tSymlink; + member.target = v.value("target", ""); + } else + return; + }; - assert(nar); - return std::string(*nar, i.start, i.size); + json v = json::parse(listing); + recurse(root, v); + } + + NarMember* find(const Path& path) { + Path canon = path == "" ? "" : canonPath(path); + NarMember* 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; + + // skip slash (canonPath above ensures that this is always a slash) + assert(*it == '/'); + it += 1; + + // 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; + current = &child->second; + + it = next; } - std::string readLink(const Path & path) override - { - auto i = get(path); - if (i.type != FSAccessor::Type::tSymlink) - throw Error(format("path '%1%' inside NAR file is not a symlink") % path); - return i.target; - } + return current; + } + + NarMember& get(const Path& path) { + auto result = find(path); + if (result == nullptr) + throw Error("NAR file does not contain path '%1%'", path); + return *result; + } + + Stat stat(const Path& path) override { + auto i = find(path); + if (i == nullptr) return {FSAccessor::Type::tMissing, 0, false}; + return {i->type, i->size, i->isExecutable, i->start}; + } + + StringSet readDirectory(const Path& path) override { + auto i = get(path); + + if (i.type != FSAccessor::Type::tDirectory) + throw Error(format("path '%1%' inside NAR file is not a directory") % + path); + + StringSet res; + for (auto& child : i.children) res.insert(child.first); + + return res; + } + + std::string readFile(const Path& path) override { + auto i = get(path); + if (i.type != FSAccessor::Type::tRegular) + throw Error(format("path '%1%' inside NAR file is not a regular file") % + path); + + if (getNarBytes) return getNarBytes(i.start, i.size); + + assert(nar); + return std::string(*nar, i.start, i.size); + } + + std::string readLink(const Path& path) override { + auto i = get(path); + if (i.type != FSAccessor::Type::tSymlink) + throw Error(format("path '%1%' inside NAR file is not a symlink") % path); + return i.target; + } }; -ref<FSAccessor> makeNarAccessor(ref<const std::string> nar) -{ - return make_ref<NarAccessor>(nar); +ref<FSAccessor> makeNarAccessor(ref<const std::string> nar) { + return make_ref<NarAccessor>(nar); } -ref<FSAccessor> makeLazyNarAccessor(const std::string & listing, - GetNarBytes getNarBytes) -{ - return make_ref<NarAccessor>(listing, getNarBytes); +ref<FSAccessor> makeLazyNarAccessor(const std::string& listing, + GetNarBytes getNarBytes) { + return make_ref<NarAccessor>(listing, getNarBytes); } -void listNar(JSONPlaceholder & res, ref<FSAccessor> accessor, - const Path & path, bool recurse) -{ - auto st = accessor->stat(path); +void listNar(JSONPlaceholder& res, ref<FSAccessor> accessor, const Path& path, + bool recurse) { + auto st = accessor->stat(path); - auto obj = res.object(); + auto obj = res.object(); - switch (st.type) { + switch (st.type) { case FSAccessor::Type::tRegular: - obj.attr("type", "regular"); - obj.attr("size", st.fileSize); - if (st.isExecutable) - obj.attr("executable", true); - if (st.narOffset) - obj.attr("narOffset", st.narOffset); - break; + obj.attr("type", "regular"); + obj.attr("size", st.fileSize); + if (st.isExecutable) obj.attr("executable", true); + if (st.narOffset) obj.attr("narOffset", st.narOffset); + break; case FSAccessor::Type::tDirectory: - obj.attr("type", "directory"); - { - auto res2 = obj.object("entries"); - for (auto & name : accessor->readDirectory(path)) { - if (recurse) { - auto res3 = res2.placeholder(name); - listNar(res3, accessor, path + "/" + name, true); - } else - res2.object(name); - } + obj.attr("type", "directory"); + { + auto res2 = obj.object("entries"); + for (auto& name : accessor->readDirectory(path)) { + if (recurse) { + auto res3 = res2.placeholder(name); + listNar(res3, accessor, path + "/" + name, true); + } else + res2.object(name); } - break; + } + break; case FSAccessor::Type::tSymlink: - obj.attr("type", "symlink"); - obj.attr("target", accessor->readLink(path)); - break; + obj.attr("type", "symlink"); + obj.attr("target", accessor->readLink(path)); + break; default: - throw Error("path '%s' does not exist in NAR", path); - } + throw Error("path '%s' does not exist in NAR", path); + } } -} +} // namespace nix |