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

View file

@ -56,6 +56,19 @@ extern PathFilter defaultPathFilter;
void dumpPath(const Path & path, Sink & sink,
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);

View file

@ -80,9 +80,9 @@ struct StringSink : Sink
/* A source that reads data from a string. */
struct StringSource : Source
{
string & s;
const string & s;
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)
{
s.copy((char *) data, len, pos);