diff options
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/archive.cc | 136 | ||||
-rw-r--r-- | src/archive.hh | 48 | ||||
-rw-r--r-- | src/hash.cc | 135 | ||||
-rw-r--r-- | src/hash.hh | 48 | ||||
-rw-r--r-- | src/nix.cc | 1 | ||||
-rw-r--r-- | src/test.cc | 1 |
7 files changed, 190 insertions, 183 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 09c2f9d09..20f172819 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,13 +3,13 @@ noinst_PROGRAMS = test AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall -I.. -nix_SOURCES = nix.cc util.cc hash.cc md5.c eval.cc values.cc globals.cc db.cc +nix_SOURCES = nix.cc util.cc hash.cc archive.cc md5.c eval.cc values.cc globals.cc db.cc nix_LDADD = -ldb_cxx-4 -lATerm #fix_SOURCES = fix.cc util.cc hash.cc md5.c #fix_LDADD = -lATerm -test_SOURCES = test.cc util.cc hash.cc md5.c eval.cc values.cc globals.cc db.cc +test_SOURCES = test.cc util.cc hash.cc archive.cc md5.c eval.cc values.cc globals.cc db.cc test_LDADD = -ldb_cxx-4 -lATerm install-data-local: diff --git a/src/archive.cc b/src/archive.cc new file mode 100644 index 000000000..2fdbfb476 --- /dev/null +++ b/src/archive.cc @@ -0,0 +1,136 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> +#include <fcntl.h> + +#include "archive.hh" +#include "util.hh" + + +static void pad(unsigned int len, DumpSink & sink) +{ + if (len % 8) { + unsigned char zero[8]; + memset(zero, 0, sizeof(zero)); + sink(zero, 8 - (len % 8)); + } +} + + +static void writeInt(unsigned int n, DumpSink & sink) +{ + unsigned char buf[8]; + memset(buf, 0, sizeof(buf)); + buf[0] = n & 0xff; + buf[1] = (n >> 8) & 0xff; + buf[2] = (n >> 16) & 0xff; + buf[3] = (n >> 24) & 0xff; + sink(buf, sizeof(buf)); +} + + +static void writeString(const string & s, DumpSink & sink) +{ + unsigned int len = s.length(); + writeInt(len, sink); + sink((const unsigned char *) s.c_str(), len); + pad(len, sink); +} + + +static void dumpEntries(const string & path, DumpSink & sink) +{ + DIR * dir = opendir(path.c_str()); + if (!dir) throw SysError("opening directory " + path); + + Strings names; + + struct dirent * dirent; + while (errno = 0, dirent = readdir(dir)) { + string name = dirent->d_name; + if (name == "." || name == "..") continue; + names.push_back(name); + } + if (errno) throw SysError("reading directory " + path); + + sort(names.begin(), names.end()); + + for (Strings::iterator it = names.begin(); + it != names.end(); it++) + { + writeString("entry", sink); + writeString("(", sink); + writeString("name", sink); + writeString(*it, sink); + writeString("file", sink); + dumpPath(path + "/" + *it, sink); + writeString(")", sink); + } + + closedir(dir); /* !!! close on exception */ +} + + +static void dumpContents(const string & path, unsigned int size, + DumpSink & sink) +{ + writeString("contents", sink); + writeInt(size, sink); + + int fd = open(path.c_str(), O_RDONLY); + if (!fd) throw SysError("opening file " + path); + + unsigned char buf[65536]; + + unsigned int total = 0; + ssize_t n; + while ((n = read(fd, buf, sizeof(buf)))) { + if (n == -1) throw SysError("reading file " + path); + total += n; + sink(buf, n); + } + + if (total != size) + throw SysError("file changed while reading it: " + path); + + pad(size, sink); + + close(fd); /* !!! close on exception */ +} + + +void dumpPath(const string & path, DumpSink & sink) +{ + struct stat st; + if (lstat(path.c_str(), &st)) + throw SysError("getting attributes of path " + path); + + writeString("(", sink); + + if (S_ISREG(st.st_mode)) { + writeString("type", sink); + writeString("regular", sink); + dumpContents(path, st.st_size, sink); + } + + else if (S_ISDIR(st.st_mode)) { + writeString("type", sink); + writeString("directory", sink); + dumpEntries(path, sink); + } + + else if (S_ISLNK(st.st_mode)) { + writeString("type", sink); + writeString("symlink", sink); + char buf[st.st_size]; + if (readlink(path.c_str(), buf, st.st_size) != st.st_size) + throw SysError("reading symbolic link " + path); + writeString("target", sink); + writeString(string(buf, st.st_size), sink); + } + + else throw Error("unknown file type: " + path); + + writeString(")", sink); +} diff --git a/src/archive.hh b/src/archive.hh new file mode 100644 index 000000000..bfd96b45c --- /dev/null +++ b/src/archive.hh @@ -0,0 +1,48 @@ +#include <string> + +using namespace std; + + +/* dumpPath creates a Nix archive of the specified path. The format + is as follows: + + IF path points to a REGULAR FILE: + dump(path) = attrs( + [ ("type", "regular") + , ("contents", contents(path)) + ]) + + IF path points to a DIRECTORY: + dump(path) = attrs( + [ ("type", "directory") + , ("entries", concat(map(f, sort(entries(path))))) + ]) + where f(fn) = attrs( + [ ("name", fn) + , ("file", dump(path + "/" + fn)) + ]) + + where: + + attrs(as) = concat(map(attr, as)) + encN(0) + attrs((a, b)) = encS(a) + encS(b) + + encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary) + + encN(n) = 64-bit little-endian encoding of n. + + contents(path) = the contents of a regular file. + + sort(strings) = lexicographic sort by 8-bit value (strcmp). + + entries(path) = the entries of a directory, without `.' and + `..'. + + `+' denotes string concatenation. */ + +struct DumpSink +{ + virtual void operator () (const unsigned char * data, unsigned int len) = 0; +}; + +void dumpPath(const string & path, DumpSink & sink); diff --git a/src/hash.cc b/src/hash.cc index fa016c835..765b7ba04 100644 --- a/src/hash.cc +++ b/src/hash.cc @@ -1,16 +1,11 @@ #include <iostream> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <dirent.h> -#include <fcntl.h> - extern "C" { #include "md5.h" } #include "hash.hh" +#include "archive.hh" Hash::Hash() @@ -117,131 +112,3 @@ Hash hashPath(const string & path) md5_finish_ctx(&sink.ctx, hash.hash); return hash; } - - -static void pad(unsigned int len, DumpSink & sink) -{ - if (len % 8) { - unsigned char zero[8]; - memset(zero, 0, sizeof(zero)); - sink(zero, 8 - (len % 8)); - } -} - - -static void writeInt(unsigned int n, DumpSink & sink) -{ - unsigned char buf[8]; - memset(buf, 0, sizeof(buf)); - buf[0] = n & 0xff; - buf[1] = (n >> 8) & 0xff; - buf[2] = (n >> 16) & 0xff; - buf[3] = (n >> 24) & 0xff; - sink(buf, sizeof(buf)); -} - - -static void writeString(const string & s, DumpSink & sink) -{ - unsigned int len = s.length(); - writeInt(len, sink); - sink((const unsigned char *) s.c_str(), len); - pad(len, sink); -} - - -static void dumpEntries(const string & path, DumpSink & sink) -{ - DIR * dir = opendir(path.c_str()); - if (!dir) throw SysError("opening directory " + path); - - Strings names; - - struct dirent * dirent; - while (errno = 0, dirent = readdir(dir)) { - string name = dirent->d_name; - if (name == "." || name == "..") continue; - names.push_back(name); - } - if (errno) throw SysError("reading directory " + path); - - sort(names.begin(), names.end()); - - for (Strings::iterator it = names.begin(); - it != names.end(); it++) - { - writeString("entry", sink); - writeString("(", sink); - writeString("name", sink); - writeString(*it, sink); - writeString("file", sink); - dumpPath(path + "/" + *it, sink); - writeString(")", sink); - } - - closedir(dir); /* !!! close on exception */ -} - - -static void dumpContents(const string & path, unsigned int size, - DumpSink & sink) -{ - writeString("contents", sink); - writeInt(size, sink); - - int fd = open(path.c_str(), O_RDONLY); - if (!fd) throw SysError("opening file " + path); - - unsigned char buf[65536]; - - unsigned int total = 0; - ssize_t n; - while ((n = read(fd, buf, sizeof(buf)))) { - if (n == -1) throw SysError("reading file " + path); - total += n; - sink(buf, n); - } - - if (total != size) - throw SysError("file changed while reading it: " + path); - - pad(size, sink); - - close(fd); /* !!! close on exception */ -} - - -void dumpPath(const string & path, DumpSink & sink) -{ - struct stat st; - if (lstat(path.c_str(), &st)) - throw SysError("getting attributes of path " + path); - - writeString("(", sink); - - if (S_ISREG(st.st_mode)) { - writeString("type", sink); - writeString("regular", sink); - dumpContents(path, st.st_size, sink); - } - - else if (S_ISDIR(st.st_mode)) { - writeString("type", sink); - writeString("directory", sink); - dumpEntries(path, sink); - } - - else if (S_ISLNK(st.st_mode)) { - writeString("type", sink); - writeString("symlink", sink); - char buf[st.st_size]; - if (readlink(path.c_str(), buf, st.st_size) != st.st_size) - throw SysError("reading symbolic link " + path); - writeString("target", sink); - writeString(string(buf, st.st_size), sink); - } - - else throw Error("unknown file type: " + path); - - writeString(")", sink); -} diff --git a/src/hash.hh b/src/hash.hh index 13c5275b4..cbc195c1f 100644 --- a/src/hash.hh +++ b/src/hash.hh @@ -47,55 +47,9 @@ Hash hashString(const string & s); Hash hashFile(const string & fileName); /* Compute the hash of the given path. The hash is defined as - follows: - - hash(path) = md5(dump(path)) + md5(dump(path)). */ Hash hashPath(const string & path); -/* Dump a path as follows: - - IF path points to a REGULAR FILE: - dump(path) = attrs( - [ ("type", "regular") - , ("contents", contents(path)) - ]) - - IF path points to a DIRECTORY: - dump(path) = attrs( - [ ("type", "directory") - , ("entries", concat(map(f, sort(entries(path))))) - ]) - where f(fn) = attrs( - [ ("name", fn) - , ("file", dump(path + "/" + fn)) - ]) - - where: - - attrs(as) = concat(map(attr, as)) + encN(0) - attrs((a, b)) = encS(a) + encS(b) - - encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary) - - encN(n) = 64-bit little-endian encoding of n. - - contents(path) = the contents of a regular file. - - sort(strings) = lexicographic sort by 8-bit value (strcmp). - - entries(path) = the entries of a directory, without `.' and - `..'. - - `+' denotes string concatenation. */ - -struct DumpSink -{ - virtual void operator () (const unsigned char * data, unsigned int len) = 0; -}; - -void dumpPath(const string & path, DumpSink & sink); - - #endif /* !__HASH_H */ diff --git a/src/nix.cc b/src/nix.cc index b2bb3bb1a..4f0b97854 100644 --- a/src/nix.cc +++ b/src/nix.cc @@ -5,6 +5,7 @@ #include "globals.hh" #include "values.hh" #include "eval.hh" +#include "archive.hh" typedef void (* Operation) (Strings opFlags, Strings opArgs); diff --git a/src/test.cc b/src/test.cc index a3706472e..2eab91d43 100644 --- a/src/test.cc +++ b/src/test.cc @@ -4,6 +4,7 @@ #include <sys/types.h> #include "hash.hh" +#include "archive.hh" #include "util.hh" #include "eval.hh" #include "values.hh" |