* 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).
This commit is contained in:
Eelco Dolstra 2010-03-09 14:32:03 +00:00
parent 44f6e6de77
commit 4c356acd04
3 changed files with 26 additions and 7 deletions

View file

@ -930,16 +930,19 @@ struct HashAndWriteSink : Sink
{ {
Sink & writeSink; Sink & writeSink;
HashSink hashSink; HashSink hashSink;
bool hashing;
HashAndWriteSink(Sink & writeSink) : writeSink(writeSink), hashSink(htSHA256) HashAndWriteSink(Sink & writeSink) : writeSink(writeSink), hashSink(htSHA256)
{ {
hashing = true;
} }
virtual void operator () virtual void operator ()
(const unsigned char * data, unsigned int len) (const unsigned char * data, unsigned int len)
{ {
writeSink(data, 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); 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); writeInt(EXPORT_MAGIC, hashAndWriteSink);
writeString(path, hashAndWriteSink); writeString(path, hashAndWriteSink);
@ -982,9 +994,8 @@ void LocalStore::exportPath(const Path & path, bool sign,
writeString(deriver, hashAndWriteSink); writeString(deriver, hashAndWriteSink);
if (sign) { if (sign) {
Hash hash = hashAndWriteSink.hashSink.finish(); Hash hash = hashAndWriteSink.currentHash();
hashAndWriteSink.hashing = false;
writeInt(1, hashAndWriteSink); writeInt(1, hashAndWriteSink);
Path tmpDir = createTempDir(); Path tmpDir = createTempDir();

View file

@ -289,6 +289,13 @@ HashSink::HashSink(HashType ht) : ht(ht)
start(ht, *ctx); start(ht, *ctx);
} }
HashSink::HashSink(const HashSink & h)
{
ht = h.ht;
ctx = new Ctx;
*ctx = *h.ctx;
}
HashSink::~HashSink() HashSink::~HashSink()
{ {
delete ctx; delete ctx;

View file

@ -96,6 +96,7 @@ private:
public: public:
HashSink(HashType ht); HashSink(HashType ht);
HashSink(const HashSink & h);
~HashSink(); ~HashSink();
virtual void operator () (const unsigned char * data, unsigned int len); virtual void operator () (const unsigned char * data, unsigned int len);
Hash finish(); Hash finish();
@ -104,5 +105,5 @@ public:
} }
#endif /* !__HASH_H */ #endif /* !__HASH_H */