From 52db1ecb3a9ad965b22b3d57eb037a27e30aad04 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Thu, 27 Feb 2025 16:08:50 +0100 Subject: [PATCH] libutil: mirror nar structure in nar visitor structure this is an unfortunate but necessary intermediate state in which we can mirror nar structure from the visitor side, but not yet from the parser side. to move from paths to entry names we must first relocate names of entries out of the entries themselves, and into their parent directory. Change-Id: I2ea898230952a4f631eea67c66ac8dcbdfb19636 --- lix/libstore/nar-accessor.cc | 41 ++++++++++++++++---------------- lix/libstore/store-api.cc | 11 ++++----- lix/libutil/archive.cc | 45 +++++++++++++++++++++++++----------- lix/libutil/archive.hh | 16 ++++++------- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/lix/libstore/nar-accessor.cc b/lix/libstore/nar-accessor.cc index fdf3ee2be..64df8c635 100644 --- a/lix/libstore/nar-accessor.cc +++ b/lix/libstore/nar-accessor.cc @@ -54,37 +54,30 @@ struct NarAccessor : public FSAccessor NarAccessor & acc; NarSource & source; - std::stack parents; + NarMember * parent; public: - NarIndexer(NarAccessor & acc, NarSource & source) - : acc(acc), source(source) + NarIndexer(NarAccessor & acc, NarSource & source, NarMember & parent) + : acc(acc), source(source), parent(&parent) { } NarMember & createMember(const Path & path, NarMember member) { - size_t level = std::count(path.begin(), path.end(), '/'); - while (parents.size() > level) parents.pop(); - - if (parents.empty()) { - acc.root = std::move(member); - parents.push(&acc.root); + if (parent->type == FSAccessor::Type::tMissing) { + *parent = std::move(member); + return *parent; } 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); + return parent->children.emplace(baseNameOf(path), std::move(member)).first->second; } - - return *parents.top(); } - void createDirectory(const Path & path) override + box_ptr createDirectory(const Path & path) override { - createMember(path, {FSAccessor::Type::tDirectory, false, 0, 0}); + auto & dir = createMember(path, {FSAccessor::Type::tDirectory, false, 0, 0}); + return make_box_ptr(acc, source, dir); } - std::unique_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override + box_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override { auto & memb = createMember(path, {FSAccessor::Type::tRegular, false, 0, 0}); @@ -93,7 +86,13 @@ struct NarAccessor : public FSAccessor memb.start = source.pos; memb.isExecutable = executable; - return std::make_unique(); + struct IgnoringFileHandle : FileHandle + { + void close() override {} + void receiveContents(std::string_view data) override {} + }; + + return make_box_ptr(); } void createSymlink(const Path & path, const std::string & target) override @@ -107,14 +106,14 @@ struct NarAccessor : public FSAccessor { StringSource source(*nar); NarSource posSource(source); - NarIndexer indexer(*this, posSource); + NarIndexer indexer(*this, posSource, root); parseDump(indexer, posSource); } NarAccessor(Source & source) { NarSource posSource(source); - NarIndexer indexer(*this, posSource); + NarIndexer indexer(*this, posSource, root); parseDump(indexer, posSource); } diff --git a/lix/libstore/store-api.cc b/lix/libstore/store-api.cc index 587827db3..c92405815 100644 --- a/lix/libstore/store-api.cc +++ b/lix/libstore/store-api.cc @@ -385,22 +385,21 @@ struct RetrieveRegularNARVisitor : NARParseVisitor sink(data); } - private: - MyFileHandle(Sink & sink) : sink(sink) {} + void close() override {} - friend struct RetrieveRegularNARVisitor; + MyFileHandle(Sink & sink) : sink(sink) {} }; Sink & sink; RetrieveRegularNARVisitor(Sink & sink) : sink(sink) { } - std::unique_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override + box_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override { - return std::unique_ptr(new MyFileHandle{sink}); + return make_box_ptr(sink); } - void createDirectory(const Path & path) override + box_ptr createDirectory(const Path & path) override { assert(false && "RetrieveRegularNARVisitor::createDirectory must not be called"); } diff --git a/lix/libutil/archive.cc b/lix/libutil/archive.cc index 292215dbb..abfb4859d 100644 --- a/lix/libutil/archive.cc +++ b/lix/libutil/archive.cc @@ -350,8 +350,8 @@ static WireFormatGenerator restore(NARParseVisitor & sink, Generator }, [&](nar::Directory d) { return [](auto d, auto & sink) -> WireFormatGenerator { - sink.createDirectory(d.path); - return restore(sink, std::move(d.contents)); + auto dir = sink.createDirectory(d.path); + co_yield restore(*dir, std::move(d.contents)); }(std::move(d), sink); }, }, @@ -407,7 +407,7 @@ struct NARRestoreVisitor : NARParseVisitor Path dstPath; private: - class MyFileHandle : public FileHandle + struct MyFileHandle : public FileHandle { AutoCloseFD fd; @@ -447,8 +447,6 @@ private: #endif } - public: - ~MyFileHandle() = default; virtual void close() override @@ -461,25 +459,26 @@ private: { writeFull(fd.get(), data); } - - friend struct NARRestoreVisitor; }; public: - void createDirectory(const Path & path) override + NARRestoreVisitor(Path dstPath): dstPath(std::move(dstPath)) {} + + box_ptr createDirectory(const Path & path) override { Path p = dstPath + path; if (mkdir(p.c_str(), 0777) == -1) throw SysError("creating directory '%1%'", p); + return make_box_ptr(dstPath); }; - std::unique_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override + box_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override { Path p = dstPath + path; AutoCloseFD fd = AutoCloseFD{open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666)}; if (!fd) throw SysError("creating file '%1%'", p); - return std::unique_ptr(new MyFileHandle(std::move(fd), size, executable)); + return make_box_ptr(std::move(fd), size, executable); } void createSymlink(const Path & path, const std::string & target) override @@ -492,8 +491,7 @@ public: void restorePath(const Path & path, Source & source) { - NARRestoreVisitor sink; - sink.dstPath = path; + NARRestoreVisitor sink(path); parseDump(sink, source); } @@ -503,7 +501,28 @@ WireFormatGenerator copyNAR(Source & source) // FIXME: if 'source' is the output of dumpPath() followed by EOF, // we should just forward all data directly without parsing. - static NARParseVisitor parseSink; /* null sink; just parse the NAR */ + struct DiscardVisitor : NARParseVisitor + { + struct MyFileHandle : FileHandle + { + void close() override {} + void receiveContents(std::string_view data) override {} + }; + + box_ptr createDirectory(const Path & path) override + { + return make_box_ptr(); + } + + box_ptr createRegularFile(const Path & path, uint64_t size, bool executable) override + { + return make_box_ptr(); + } + + void createSymlink(const Path & path, const std::string & target) override {} + }; + + static DiscardVisitor parseSink; /* null sink; just parse the NAR */ return parseAndCopyDump(parseSink, source); } diff --git a/lix/libutil/archive.hh b/lix/libutil/archive.hh index a594ecc09..6d9f841c1 100644 --- a/lix/libutil/archive.hh +++ b/lix/libutil/archive.hh @@ -93,30 +93,28 @@ struct NARParseVisitor FileHandle & operator=(FileHandle &) = delete; /** Puts one block of data into the file */ - virtual void receiveContents(std::string_view data) { } + virtual void receiveContents(std::string_view data) = 0; /** * Explicitly closes the file. Further operations may throw an assert. * This exists so that closing can fail and throw an exception without doing so in a destructor. */ - virtual void close() { } + virtual void close() = 0; virtual ~FileHandle() = default; }; - virtual void createDirectory(const Path & path) { } + virtual ~NARParseVisitor() = default; + + virtual box_ptr createDirectory(const Path & path) = 0; /** * Creates a regular file in the extraction output with the given size and executable flag. * The size is guaranteed to be the true size of the file. */ - [[nodiscard]] - virtual std::unique_ptr createRegularFile(const Path & path, uint64_t size, bool executable) - { - return std::make_unique(); - } + virtual box_ptr createRegularFile(const Path & path, uint64_t size, bool executable) = 0; - virtual void createSymlink(const Path & path, const std::string & target) { } + virtual void createSymlink(const Path & path, const std::string & target) = 0; }; namespace nar {