* A simple API for parsing NAR archives.

This commit is contained in:
Eelco Dolstra 2008-12-03 17:30:32 +00:00
parent cdee317419
commit 5eaf644c99
3 changed files with 80 additions and 26 deletions

View file

@ -129,10 +129,11 @@ static void skipGeneric(Source & source)
} }
static void restore(const Path & path, Source & source); static void parse(ParseSink & sink, Source & source, const Path & path);
static void restoreEntry(const Path & path, Source & source)
static void parseEntry(ParseSink & sink, Source & source, const Path & path)
{ {
string s, name; string s, name;
@ -150,7 +151,7 @@ static void restoreEntry(const Path & path, Source & source)
name = readString(source); name = readString(source);
} else if (s == "node") { } else if (s == "node") {
if (s == "") throw badArchive("entry name missing"); if (s == "") throw badArchive("entry name missing");
restore(path + "/" + name, source); parse(sink, source, path + "/" + name);
} else { } else {
throw badArchive("unknown field " + s); throw badArchive("unknown field " + s);
skipGeneric(source); skipGeneric(source);
@ -159,7 +160,7 @@ static void restoreEntry(const Path & path, Source & source)
} }
static void restoreContents(int fd, const Path & path, Source & source) static void parseContents(ParseSink & sink, Source & source, const Path & path)
{ {
unsigned int size = readInt(source); unsigned int size = readInt(source);
unsigned int left = size; unsigned int left = size;
@ -170,7 +171,7 @@ static void restoreContents(int fd, const Path & path, Source & source)
unsigned int n = sizeof(buf); unsigned int n = sizeof(buf);
if (n > left) n = left; if (n > left) n = left;
source(buf, n); source(buf, n);
writeFull(fd, buf, n); sink.receiveContents(buf, n);
left -= n; left -= n;
} }
@ -178,7 +179,7 @@ static void restoreContents(int fd, const Path & path, Source & source)
} }
static void restore(const Path & path, Source & source) static void parse(ParseSink & sink, Source & source, const Path & path)
{ {
string s; string s;
@ -186,7 +187,6 @@ static void restore(const Path & path, Source & source)
if (s != "(") throw badArchive("expected open tag"); if (s != "(") throw badArchive("expected open tag");
enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown; enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;
AutoCloseFD fd;
while (1) { while (1) {
checkInterrupt(); checkInterrupt();
@ -204,15 +204,12 @@ static void restore(const Path & path, Source & source)
if (t == "regular") { if (t == "regular") {
type = tpRegular; type = tpRegular;
fd = open(path.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666); sink.createRegularFile(path);
if (fd == -1)
throw SysError("creating file " + path);
} }
else if (t == "directory") { else if (t == "directory") {
sink.createDirectory(path);
type = tpDirectory; type = tpDirectory;
if (mkdir(path.c_str(), 0777) == -1)
throw SysError("creating directory " + path);
} }
else if (t == "symlink") { else if (t == "symlink") {
@ -224,11 +221,60 @@ static void restore(const Path & path, Source & source)
} }
else if (s == "contents" && type == tpRegular) { else if (s == "contents" && type == tpRegular) {
restoreContents(fd, path, source); parseContents(sink, source, path);
} }
else if (s == "executable" && type == tpRegular) { else if (s == "executable" && type == tpRegular) {
readString(source); readString(source);
sink.isExecutable();
}
else if (s == "entry" && type == tpDirectory) {
parseEntry(sink, source, path);
}
else if (s == "target" && type == tpSymlink) {
string target = readString(source);
sink.createSymlink(path, target);
}
else {
throw badArchive("unknown field " + s);
skipGeneric(source);
}
}
}
void parseDump(ParseSink & sink, Source & source)
{
if (readString(source) != archiveVersion1)
throw badArchive("expected Nix archive");
parse(sink, source, "");
}
struct RestoreSink : ParseSink
{
Path dstPath;
AutoCloseFD fd;
void createDirectory(const Path & path)
{
Path p = dstPath + path;
if (mkdir(p.c_str(), 0777) == -1)
throw SysError(format("creating directory `%1%'") % p);
};
void createRegularFile(const Path & path)
{
Path p = dstPath + path;
fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd == -1) throw SysError(format("creating file `%1%'") % p);
}
void isExecutable()
{
struct stat st; struct stat st;
if (fstat(fd, &st) == -1) if (fstat(fd, &st) == -1)
throw SysError("fstat"); throw SysError("fstat");
@ -236,30 +282,25 @@ static void restore(const Path & path, Source & source)
throw SysError("fchmod"); throw SysError("fchmod");
} }
else if (s == "entry" && type == tpDirectory) { void receiveContents(unsigned char * data, unsigned int len)
restoreEntry(path, source); {
writeFull(fd, data, len);
} }
else if (s == "target" && type == tpSymlink) { void createSymlink(const Path & path, const string & target)
string target = readString(source); {
if (symlink(target.c_str(), path.c_str()) == -1) Path p = dstPath + path;
throw SysError("creating symlink " + path); if (symlink(target.c_str(), p.c_str()) == -1)
} throw SysError(format("creating symlink `%1%'") % p);
else {
throw badArchive("unknown field " + s);
skipGeneric(source);
}
}
} }
};
void restorePath(const Path & path, Source & source) void restorePath(const Path & path, Source & source)
{ {
if (readString(source) != archiveVersion1) RestoreSink sink;
throw badArchive("expected Nix archive"); sink.dstPath = path;
restore(path, source); parseDump(sink, source);
} }

View file

@ -56,6 +56,19 @@ extern PathFilter defaultPathFilter;
void dumpPath(const Path & path, Sink & sink, void dumpPath(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter); PathFilter & filter = defaultPathFilter);
struct ParseSink
{
virtual void createDirectory(const Path & path) { };
virtual void createRegularFile(const Path & path) { };
virtual void isExecutable() { };
virtual void receiveContents(unsigned char * data, unsigned int len) { };
virtual void createSymlink(const Path & path, const string & target) { };
};
void parseDump(ParseSink & sink, Source & source);
void restorePath(const Path & path, Source & source); void restorePath(const Path & path, Source & source);

View file

@ -80,9 +80,9 @@ struct StringSink : Sink
/* A source that reads data from a string. */ /* A source that reads data from a string. */
struct StringSource : Source struct StringSource : Source
{ {
string & s; const string & s;
unsigned int pos; unsigned int pos;
StringSource(string & _s) : s(_s), pos(0) { } StringSource(const string & _s) : s(_s), pos(0) { }
virtual void operator () (unsigned char * data, unsigned int len) virtual void operator () (unsigned char * data, unsigned int len)
{ {
s.copy((char *) data, len, pos); s.copy((char *) data, len, pos);