aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/archive.cc
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-05-15 16:45:46 +0200
committereldritch horrors <pennae@lix.systems>2024-07-11 20:37:27 +0000
commit03db4efab90b72c15cb5513debb3ad1563e70cf7 (patch)
tree6420f401d1b0dda1491eed854380cf71d77b087f /src/libutil/archive.cc
parent31478c810a79403fbb670ef7c4ef1d0d48271c80 (diff)
libstore: turn the NAR parser into a passthrough generator
this will let us turn copyNAR into a generator as well, which in turn is necessary to turn the users of copyNAR into generators without resorting to sinkToSource coroutines. currently this uses the SerializingTransform in all cases, even for copyNAR where it is not necessary. should this be a performance problem we can easily swap out the transform for one which does not produce any bytes of its own, but that should not be necessary. Change-Id: I7e685879318fcbb78d8b88abfddd7752360eb0ce
Diffstat (limited to 'src/libutil/archive.cc')
-rw-r--r--src/libutil/archive.cc32
1 files changed, 25 insertions, 7 deletions
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 2ac9f3dcd..1b8038649 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -174,9 +174,10 @@ static void skipGeneric(Source & source)
#endif
-static void parseContents(ParseSink & sink, Source & source, const Path & path)
+static WireFormatGenerator parseContents(ParseSink & sink, Source & source, const Path & path)
{
uint64_t size = readLongLong(source);
+ co_yield size;
sink.preallocateContents(size);
@@ -188,11 +189,13 @@ static void parseContents(ParseSink & sink, Source & source, const Path & path)
auto n = buf.size();
if ((uint64_t)n > left) n = left;
source(buf.data(), n);
+ co_yield std::span{buf.data(), n};
sink.receiveContents({buf.data(), n});
left -= n;
}
readPadding(size, source);
+ co_yield SerializingTransform::padding(size);
}
@@ -204,12 +207,12 @@ struct CaseInsensitiveCompare
}
};
-
-static void parse(ParseSink & sink, Source & source, const Path & path)
+static WireFormatGenerator parse(ParseSink & sink, Source & source, const Path & path)
{
std::string s;
s = readString(source);
+ co_yield s;
if (s != "(") throw badArchive("expected open tag");
enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;
@@ -220,6 +223,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
checkInterrupt();
s = readString(source);
+ co_yield s;
if (s == ")") {
break;
@@ -229,6 +233,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
if (type != tpUnknown)
throw badArchive("multiple type fields");
std::string t = readString(source);
+ co_yield t;
if (t == "regular") {
type = tpRegular;
@@ -249,12 +254,13 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
}
else if (s == "contents" && type == tpRegular) {
- parseContents(sink, source, path);
+ co_yield parseContents(sink, source, path);
sink.closeRegularFile();
}
else if (s == "executable" && type == tpRegular) {
auto s = readString(source);
+ co_yield s;
if (s != "") throw badArchive("executable marker has non-empty value");
sink.isExecutable();
}
@@ -263,17 +269,20 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
std::string name, prevName;
s = readString(source);
+ co_yield s;
if (s != "(") throw badArchive("expected open tag");
while (1) {
checkInterrupt();
s = readString(source);
+ co_yield s;
if (s == ")") {
break;
} else if (s == "name") {
name = readString(source);
+ co_yield name;
if (name.empty() || name == "." || name == ".." || name.find('/') != std::string::npos || name.find((char) 0) != std::string::npos)
throw Error("NAR contains invalid file name '%1%'", name);
if (name <= prevName)
@@ -290,7 +299,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
}
} else if (s == "node") {
if (name.empty()) throw badArchive("entry name missing");
- parse(sink, source, path + "/" + name);
+ co_yield parse(sink, source, path + "/" + name);
} else
throw badArchive("unknown field " + s);
}
@@ -298,6 +307,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
else if (s == "target" && type == tpSymlink) {
std::string target = readString(source);
+ co_yield target;
sink.createSymlink(path, target);
}
@@ -307,20 +317,28 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
}
-void parseDump(ParseSink & sink, Source & source)
+WireFormatGenerator parseAndCopyDump(ParseSink & sink, Source & source)
{
std::string version;
try {
version = readString(source, narVersionMagic1.size());
+ co_yield version;
} catch (SerialisationError & e) {
/* This generally means the integer at the start couldn't be
decoded. Ignore and throw the exception below. */
}
if (version != narVersionMagic1)
throw badArchive("input doesn't look like a Nix archive");
- parse(sink, source, "");
+ co_yield parse(sink, source, "");
}
+void parseDump(ParseSink & sink, Source & source)
+{
+ auto parser = parseAndCopyDump(sink, source);
+ while (parser.next()) {
+ // ignore the actual item
+ }
+}
struct RestoreSink : ParseSink
{