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
7 changes: 6 additions & 1 deletion src/libutil/archive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ static void parseContents(CreateRegularFileSink & sink, Source & source)

sink.preallocateContents(size);

if (sink.skipContents) {
source.skip(size + (size % 8 ? 8 - (size % 8) : 0));
return;
}

uint64_t left = size;
std::array<char, 65536> buf;

Expand Down Expand Up @@ -166,7 +171,7 @@ static void parse(FileSystemObjectSink & sink, Source & source, const CanonPath
auto expectTag = [&](std::string_view expected) {
auto tag = getString();
if (tag != expected)
throw badArchive("expected tag '%s', got '%s'", expected, tag);
throw badArchive("expected tag '%s', got '%s'", expected, tag.substr(0, 1024));
};

expectTag("(");
Expand Down
2 changes: 2 additions & 0 deletions src/libutil/fs-sink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ void NullFileSystemObjectSink::createRegularFile(
void isExecutable() override {}
} crf;

crf.skipContents = true;

// Even though `NullFileSystemObjectSink` doesn't do anything, it's important
// that we call the function, to e.g. advance the parser using this
// sink.
Expand Down
8 changes: 8 additions & 0 deletions src/libutil/include/nix/util/fs-sink.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ namespace nix {
*/
struct CreateRegularFileSink : Sink
{
/**
* If set to true, the sink will not be called with the contents
* of the file. `preallocateContents()` will still be called to
* convey the file size. Useful for sinks that want to efficiently
* discard the contents of the file.
*/
bool skipContents = false;

virtual void isExecutable() = 0;

/**
Expand Down
5 changes: 5 additions & 0 deletions src/libutil/include/nix/util/serialise.hh
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ struct Source
void drainInto(Sink & sink);

std::string drain();

virtual void skip(size_t len);
};

/**
Expand Down Expand Up @@ -177,6 +179,7 @@ struct FdSource : BufferedSource
Descriptor fd;
size_t read = 0;
BackedStringView endOfFileError{"unexpected end-of-file"};
bool isSeekable = true;

FdSource()
: fd(INVALID_DESCRIPTOR)
Expand All @@ -200,6 +203,8 @@ struct FdSource : BufferedSource
*/
bool hasData();

void skip(size_t len) override;

protected:
size_t readUnbuffered(char * data, size_t len) override;
private:
Expand Down
48 changes: 45 additions & 3 deletions src/libutil/serialise.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,8 @@ void Source::drainInto(Sink & sink)
{
std::array<char, 8192> buf;
while (true) {
size_t n;
try {
n = read(buf.data(), buf.size());
auto n = read(buf.data(), buf.size());
sink({buf.data(), n});
} catch (EndOfFile &) {
break;
Expand All @@ -111,6 +110,16 @@ std::string Source::drain()
return std::move(s.s);
}

void Source::skip(size_t len)
{
std::array<char, 8192> buf;
while (len) {
auto n = read(buf.data(), std::min(len, buf.size()));
assert(n <= len);
len -= n;
}
}

size_t BufferedSource::read(char * data, size_t len)
{
if (!buffer)
Expand All @@ -120,7 +129,7 @@ size_t BufferedSource::read(char * data, size_t len)
bufPosIn = readUnbuffered(buffer.get(), bufSize);

/* Copy out the data in the buffer. */
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
auto n = std::min(len, bufPosIn - bufPosOut);
memcpy(data, buffer.get() + bufPosOut, n);
bufPosOut += n;
if (bufPosIn == bufPosOut)
Expand Down Expand Up @@ -191,6 +200,39 @@ bool FdSource::hasData()
}
}

void FdSource::skip(size_t len)
{
/* Discard data in the buffer. */
if (len && buffer && bufPosIn - bufPosOut) {
if (len >= bufPosIn - bufPosOut) {
len -= bufPosIn - bufPosOut;
bufPosIn = bufPosOut = 0;
} else {
bufPosOut += len;
len = 0;
}
}

#ifndef _WIN32
/* If we can, seek forward in the file to skip the rest. */
if (isSeekable && len) {
if (lseek(fd, len, SEEK_CUR) == -1) {
if (errno == ESPIPE)
isSeekable = false;
else
throw SysError("seeking forward in file");
} else {
read += len;
return;
}
}
#endif

/* Otherwise, skip by reading. */
if (len)
BufferedSource::skip(len);
}

size_t StringSource::read(char * data, size_t len)
{
if (pos == s.size())
Expand Down
12 changes: 10 additions & 2 deletions src/nix/dump-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

using namespace nix;

static FdSink getNarSink()
{
auto fd = getStandardOutput();
if (isatty(fd))
throw UsageError("refusing to write NAR to a terminal");
return FdSink(std::move(fd));
}

struct CmdDumpPath : StorePathCommand
{
std::string description() override
Expand All @@ -20,7 +28,7 @@ struct CmdDumpPath : StorePathCommand

void run(ref<Store> store, const StorePath & storePath) override
{
FdSink sink(getStandardOutput());
auto sink = getNarSink();
store->narFromPath(storePath, sink);
sink.flush();
}
Expand Down Expand Up @@ -51,7 +59,7 @@ struct CmdDumpPath2 : Command

void run() override
{
FdSink sink(getStandardOutput());
auto sink = getNarSink();
dumpPath(path, sink);
sink.flush();
}
Expand Down
27 changes: 26 additions & 1 deletion src/nix/nario-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,37 @@ R""(
* List the contents of a nario file:

```console
# nix nario list < dump
# nix nario list < dump.nario
/nix/store/4y1jj6cwvslmfh1bzkhbvhx77az6yf00-xgcc-14.2.1.20250322-libgcc: 201856 bytes
/nix/store/d8hnbm5hvbg2vza50garppb63y724i94-libunistring-1.3: 2070240 bytes
```

* Use `--json` to get detailed information in JSON format:

```console
# nix nario list --json < dump.nario
{
"paths": {
"/nix/store/m1r53pnn…-hello-2.12.1": {
"ca": null,
"deriver": "/nix/store/qa8is0vm…-hello-2.12.1.drv",
"narHash": "sha256-KSCYs4J7tFa+oX7W5M4D7ZYNvrWtdcWTdTL5fQk+za8=",
"narSize": 234672,
"references": [
"/nix/store/g8zyryr9…-glibc-2.40-66",
"/nix/store/m1r53pnn…-hello-2.12.1"
],
"registrationTime": 1756900709,
"signatures": [ "cache.nixos.org-1:QbG7A…" ],
"ultimate": false
},
},
"version": 1
}
```

# Description

This command lists the contents of a nario file read from standard input.
Expand Down
Loading