aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am4
-rw-r--r--src/archive.cc136
-rw-r--r--src/archive.hh48
-rw-r--r--src/hash.cc135
-rw-r--r--src/hash.hh48
-rw-r--r--src/nix.cc1
-rw-r--r--src/test.cc1
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"