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 {