* A simple API for parsing NAR archives.
This commit is contained in:
parent
cdee317419
commit
5eaf644c99
3 changed files with 80 additions and 26 deletions
|
@ -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,42 +221,86 @@ 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);
|
||||||
struct stat st;
|
sink.isExecutable();
|
||||||
if (fstat(fd, &st) == -1)
|
|
||||||
throw SysError("fstat");
|
|
||||||
if (fchmod(fd, st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
|
|
||||||
throw SysError("fchmod");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (s == "entry" && type == tpDirectory) {
|
else if (s == "entry" && type == tpDirectory) {
|
||||||
restoreEntry(path, source);
|
parseEntry(sink, source, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (s == "target" && type == tpSymlink) {
|
else if (s == "target" && type == tpSymlink) {
|
||||||
string target = readString(source);
|
string target = readString(source);
|
||||||
if (symlink(target.c_str(), path.c_str()) == -1)
|
sink.createSymlink(path, target);
|
||||||
throw SysError("creating symlink " + path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
throw badArchive("unknown field " + s);
|
throw badArchive("unknown field " + s);
|
||||||
skipGeneric(source);
|
skipGeneric(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void restorePath(const Path & path, Source & source)
|
void parseDump(ParseSink & sink, Source & source)
|
||||||
{
|
{
|
||||||
if (readString(source) != archiveVersion1)
|
if (readString(source) != archiveVersion1)
|
||||||
throw badArchive("expected Nix archive");
|
throw badArchive("expected Nix archive");
|
||||||
restore(path, source);
|
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");
|
||||||
|
if (fchmod(fd, st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
|
||||||
|
throw SysError("fchmod");
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiveContents(unsigned char * data, unsigned int len)
|
||||||
|
{
|
||||||
|
writeFull(fd, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
RestoreSink sink;
|
||||||
|
sink.dstPath = path;
|
||||||
|
parseDump(sink, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue