diff --git a/src/libutil/include/nix/util/nar-accessor.hh b/src/libutil/include/nix/util/nar-accessor.hh index 5488f21b5..745c79f60 100644 --- a/src/libutil/include/nix/util/nar-accessor.hh +++ b/src/libutil/include/nix/util/nar-accessor.hh @@ -32,8 +32,16 @@ using GetNarBytes = std::function; */ GetNarBytes seekableGetNarBytes(const Path & path); +GetNarBytes seekableGetNarBytes(Descriptor fd); + ref makeLazyNarAccessor(const nlohmann::json & listing, GetNarBytes getNarBytes); +/** + * Creates a NAR accessor from a given stream and a GetNarBytes getter. + * @param source Consumed eagerly. References to it are not persisted in the resulting SourceAccessor. + */ +ref makeLazyNarAccessor(Source & source, GetNarBytes getNarBytes); + struct NarListingRegularFile { /** diff --git a/src/libutil/nar-accessor.cc b/src/libutil/nar-accessor.cc index 22b6abdd5..5644ca408 100644 --- a/src/libutil/nar-accessor.cc +++ b/src/libutil/nar-accessor.cc @@ -111,6 +111,7 @@ struct NarAccessor : public SourceAccessor path, NarMember{.stat = {.type = Type::tRegular, .fileSize = 0, .isExecutable = false, .narOffset = 0}}); NarMemberConstructor nmc{nm, pos}; + nmc.skipContents = true; /* Don't care about contents. */ func(nmc); } @@ -141,6 +142,13 @@ struct NarAccessor : public SourceAccessor parseDump(indexer, indexer); } + NarAccessor(Source & source, GetNarBytes getNarBytes) + : getNarBytes(std::move(getNarBytes)) + { + NarIndexer indexer(*this, source); + parseDump(indexer, indexer); + } + NarAccessor(const nlohmann::json & listing, GetNarBytes getNarBytes) : getNarBytes(getNarBytes) { @@ -249,24 +257,35 @@ ref makeLazyNarAccessor(const nlohmann::json & listing, GetNarBy return make_ref(listing, getNarBytes); } +ref makeLazyNarAccessor(Source & source, GetNarBytes getNarBytes) +{ + return make_ref(source, getNarBytes); +} + GetNarBytes seekableGetNarBytes(const Path & path) { - return [path](uint64_t offset, uint64_t length) { - AutoCloseFD fd = toDescriptor(open( - path.c_str(), - O_RDONLY -#ifndef _WIN32 - | O_CLOEXEC + AutoCloseFD fd = toDescriptor(open( + path.c_str(), + O_RDONLY +#ifdef O_CLOEXEC + | O_CLOEXEC #endif - )); - if (!fd) - throw SysError("opening NAR cache file '%s'", path); + )); + if (!fd) + throw SysError("opening NAR cache file '%s'", path); - if (lseek(fromDescriptorReadOnly(fd.get()), offset, SEEK_SET) != (off_t) offset) - throw SysError("seeking in '%s'", path); + return [inner = seekableGetNarBytes(fd.get()), fd = make_ref(std::move(fd))]( + uint64_t offset, uint64_t length) { return inner(offset, length); }; +} + +GetNarBytes seekableGetNarBytes(Descriptor fd) +{ + return [fd](uint64_t offset, uint64_t length) { + if (::lseek(fromDescriptorReadOnly(fd), offset, SEEK_SET) == -1) + throw SysError("seeking in file"); std::string buf(length, 0); - readFull(fd.get(), buf.data(), length); + readFull(fd, buf.data(), length); return buf; }; diff --git a/src/nix/cat.cc b/src/nix/cat.cc index 812dfdbcf..f0dfc3ee6 100644 --- a/src/nix/cat.cc +++ b/src/nix/cat.cc @@ -79,9 +79,7 @@ struct CmdCatNar : StoreCommand, MixCat if (!fd) throw SysError("opening NAR file '%s'", narPath); auto source = FdSource{fd.get()}; - auto narAccessor = makeNarAccessor(source); - nlohmann::json listing = listNarDeep(*narAccessor, CanonPath::root); - cat(makeLazyNarAccessor(listing, seekableGetNarBytes(narPath)), CanonPath{path}); + cat(makeLazyNarAccessor(source, seekableGetNarBytes(fd.get())), CanonPath{path}); } }; diff --git a/src/nix/ls.cc b/src/nix/ls.cc index fd4a98d7a..66f52a18a 100644 --- a/src/nix/ls.cc +++ b/src/nix/ls.cc @@ -154,9 +154,7 @@ struct CmdLsNar : Command, MixLs if (!fd) throw SysError("opening NAR file '%s'", narPath); auto source = FdSource{fd.get()}; - auto narAccessor = makeNarAccessor(source); - nlohmann::json listing = listNarDeep(*narAccessor, CanonPath::root); - list(makeLazyNarAccessor(listing, seekableGetNarBytes(narPath)), CanonPath{path}); + list(makeLazyNarAccessor(source, seekableGetNarBytes(fd.get())), CanonPath{path}); } };