about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-03-09T14·32+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-03-09T14·32+0000
commit4c356acd044dffbf459ac895b483b49959042931 (patch)
treef5a9d5ee7f9092a860e28415287de0cb0ac37cf4
parent44f6e6de77dd318800775d594b1f33cffa2be9a5 (diff)
* In `nix-store --export', abort if the contents of a path has
  changed.  This prevents corrupt paths from spreading to other
  machines.  Note that checking the hash is cheap because we're
  hashing anyway (because of the --sign feature).

-rw-r--r--src/libstore/local-store.cc23
-rw-r--r--src/libutil/hash.cc7
-rw-r--r--src/libutil/hash.hh3
3 files changed, 26 insertions, 7 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index c7232056f8ed..ff7196644182 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -930,16 +930,19 @@ struct HashAndWriteSink : Sink
 {
     Sink & writeSink;
     HashSink hashSink;
-    bool hashing;
     HashAndWriteSink(Sink & writeSink) : writeSink(writeSink), hashSink(htSHA256)
     {
-        hashing = true;
     }
     virtual void operator ()
         (const unsigned char * data, unsigned int len)
     {
         writeSink(data, len);
-        if (hashing) hashSink(data, len);
+        hashSink(data, len);
+    }
+    Hash currentHash()
+    {
+        HashSink hashSinkClone(hashSink);
+        return hashSinkClone.finish();
     }
 };
 
@@ -970,6 +973,15 @@ void LocalStore::exportPath(const Path & path, bool sign,
     
     dumpPath(path, hashAndWriteSink);
 
+    /* Refuse to export paths that have changed.  This prevents
+       filesystem corruption from spreading to other machines. */
+    Hash hash = hashAndWriteSink.currentHash();
+    Hash storedHash = queryPathHash(path);
+    if (hash != storedHash)
+        throw Error(format("hash of path `%1%' has changed from `%2%' to `%3%'!") % path
+            % printHash(storedHash) % printHash(hash));
+    printMsg(lvlError, printHash(hash));
+
     writeInt(EXPORT_MAGIC, hashAndWriteSink);
 
     writeString(path, hashAndWriteSink);
@@ -982,9 +994,8 @@ void LocalStore::exportPath(const Path & path, bool sign,
     writeString(deriver, hashAndWriteSink);
 
     if (sign) {
-        Hash hash = hashAndWriteSink.hashSink.finish();
-        hashAndWriteSink.hashing = false;
-
+        Hash hash = hashAndWriteSink.currentHash();
+ 
         writeInt(1, hashAndWriteSink);
         
         Path tmpDir = createTempDir();
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index eef01fe4d609..bd7e33a48e70 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -289,6 +289,13 @@ HashSink::HashSink(HashType ht) : ht(ht)
     start(ht, *ctx);
 }
     
+HashSink::HashSink(const HashSink & h)
+{
+    ht = h.ht;
+    ctx = new Ctx;
+    *ctx = *h.ctx;
+}
+    
 HashSink::~HashSink()
 {
     delete ctx;
diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh
index 062d97254bfc..81425b23494c 100644
--- a/src/libutil/hash.hh
+++ b/src/libutil/hash.hh
@@ -96,6 +96,7 @@ private:
 
 public:
     HashSink(HashType ht);
+    HashSink(const HashSink & h);
     ~HashSink();
     virtual void operator () (const unsigned char * data, unsigned int len);
     Hash finish();
@@ -104,5 +105,5 @@ public:
 
 }
 
-    
+
 #endif /* !__HASH_H */