about summary refs log tree commit diff
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 09c2f9d09363..20f172819f41 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 000000000000..2fdbfb47649c
--- /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 000000000000..bfd96b45c03e
--- /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 fa016c8359df..765b7ba04a39 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 13c5275b468a..cbc195c1fb98 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 b2bb3bb1aba6..4f0b97854b67 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 a3706472ee6d..2eab91d43bb4 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"