* 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:
parent
44f6e6de77
commit
4c356acd04
3 changed files with 26 additions and 7 deletions
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue