Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions src/libutil/file-system.cc
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,7 @@ std::string readFile(const Path & path)
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_RDONLY
// TODO
#ifndef _WIN32
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
));
Expand Down Expand Up @@ -294,8 +293,7 @@ void readFile(const Path & path, Sink & sink, bool memory_map)
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_RDONLY
// TODO
#ifndef _WIN32
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
));
Expand All @@ -309,8 +307,7 @@ void writeFile(const Path & path, std::string_view s, mode_t mode, FsSync sync)
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_WRONLY | O_TRUNC | O_CREAT
// TODO
#ifndef _WIN32
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
,
Expand Down Expand Up @@ -344,8 +341,7 @@ void writeFile(const Path & path, Source & source, mode_t mode, FsSync sync)
AutoCloseFD fd = toDescriptor(open(
path.c_str(),
O_WRONLY | O_TRUNC | O_CREAT
// TODO
#ifndef _WIN32
#ifdef O_CLOEXEC
| O_CLOEXEC
#endif
,
Expand Down
2 changes: 1 addition & 1 deletion src/libutil/include/nix/util/fs-sink.hh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace nix {
*
* See `FileSystemObjectSink::createRegularFile`.
*/
struct CreateRegularFileSink : Sink
struct CreateRegularFileSink : virtual Sink
{
/**
* If set to true, the sink will not be called with the contents
Expand Down
8 changes: 8 additions & 0 deletions src/libutil/include/nix/util/nar-accessor.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,16 @@ using GetNarBytes = std::function<std::string(uint64_t, uint64_t)>;
*/
GetNarBytes seekableGetNarBytes(const Path & path);

GetNarBytes seekableGetNarBytes(Descriptor fd);

ref<SourceAccessor> makeLazyNarAccessor(const nlohmann::json & listing, GetNarBytes getNarBytes);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW this should use the new listing types now that we have them (I missed them before)


/**
* 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<SourceAccessor> makeLazyNarAccessor(Source & source, GetNarBytes getNarBytes);

struct NarListingRegularFile
{
/**
Expand Down
43 changes: 31 additions & 12 deletions src/libutil/nar-accessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -249,24 +257,35 @@ ref<SourceAccessor> makeLazyNarAccessor(const nlohmann::json & listing, GetNarBy
return make_ref<NarAccessor>(listing, getNarBytes);
}

ref<SourceAccessor> makeLazyNarAccessor(Source & source, GetNarBytes getNarBytes)
{
return make_ref<NarAccessor>(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<AutoCloseFD>(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;
};
Expand Down
38 changes: 35 additions & 3 deletions src/nix/cat.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "nix/cmd/command.hh"
#include "nix/store/store-api.hh"
#include "nix/util/archive.hh"
#include "nix/util/nar-accessor.hh"
#include "nix/util/serialise.hh"
#include "nix/util/source-accessor.hh"
Expand Down Expand Up @@ -79,9 +80,40 @@ 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});

struct CatRegularFileSink : NullFileSystemObjectSink
{
CanonPath neededPath = CanonPath::root;
bool found = false;

void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> crf) override
{
struct : CreateRegularFileSink, FdSink
{
void isExecutable() override {}
} crfSink;

crfSink.fd = INVALID_DESCRIPTOR;

if (path == neededPath) {
logger->stop();
crfSink.skipContents = false;
crfSink.fd = STDOUT_FILENO;
found = true;
} else {
crfSink.skipContents = true;
}

crf(crfSink);
}
} sink;

sink.neededPath = CanonPath(path);
/* NOTE: We still parse the whole file to validate that it's a correct NAR. */
parseDump(sink, source);

if (!sink.found)
throw Error("NAR does not contain regular file '%1%'", path);
}
};

Expand Down
4 changes: 1 addition & 3 deletions src/nix/ls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}
};

Expand Down
2 changes: 2 additions & 0 deletions tests/functional/nar-access.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ diff -u data.cat-nar "$storePath/foo/data"
# Check that file contents of baz match.
nix nar cat "$narFile" /foo/baz > baz.cat-nar
diff -u baz.cat-nar "$storePath/foo/baz"
nix nar cat /dev/stdin /foo/baz < "$narFile" > baz.cat-nar-pipe
expect 1 nix nar cat "$narFile" /foo/baz/doesntexist 2>&1 | grep "NAR does not contain regular file '/foo/baz/doesntexist'"

nix store cat "$storePath/foo/baz" > baz.cat-nar
diff -u baz.cat-nar "$storePath/foo/baz"
Expand Down
Loading