* 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,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); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue