From 538a64e8c314f23ba0c5d76201f1c20e71884a21 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 4 May 2016 13:36:54 +0200 Subject: Add a Store::addToStore() variant that accepts a NAR As a side effect, this ensures that signatures are propagated when copying paths between stores. Also refactored import/export to make use of this. --- src/libstore/local-store.cc | 194 ++++++++------------------------------------ 1 file changed, 34 insertions(+), 160 deletions(-) (limited to 'src/libstore/local-store.cc') diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 42e4ab9f4aff..ff434d058992 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -901,6 +901,40 @@ void LocalStore::invalidatePath(State & state, const Path & path) } +void LocalStore::addToStore(const ValidPathInfo & info, const std::string & nar, bool repair) +{ + addTempRoot(info.path); + + if (repair || !isValidPath(info.path)) { + + PathLocks outputLock; + + /* Lock the output path. But don't lock if we're being called + from a build hook (whose parent process already acquired a + lock on this path). */ + Strings locksHeld = tokenizeString(getEnv("NIX_HELD_LOCKS")); + if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end()) + outputLock.lockPaths({info.path}); + + if (repair || !isValidPath(info.path)) { + + deletePath(info.path); + + StringSource source(nar); + restorePath(info.path, source); + + canonicalisePathMetaData(info.path, -1); + + optimisePath(info.path); // FIXME: combine with hashPath() + + registerValidPath(info); + } + + outputLock.setDeletion(true); + } +} + + Path LocalStore::addToStoreFromDump(const string & dump, const string & name, bool recursive, HashType hashAlgo, bool repair) { @@ -1016,69 +1050,6 @@ Path LocalStore::addTextToStore(const string & name, const string & s, } -struct HashAndWriteSink : Sink -{ - Sink & writeSink; - HashSink hashSink; - HashAndWriteSink(Sink & writeSink) : writeSink(writeSink), hashSink(htSHA256) - { - } - virtual void operator () (const unsigned char * data, size_t len) - { - writeSink(data, len); - hashSink(data, len); - } - Hash currentHash() - { - return hashSink.currentHash().first; - } -}; - - -void LocalStore::exportPath(const Path & path, Sink & sink) -{ - assertStorePath(path); - - printMsg(lvlTalkative, format("exporting path ‘%1%’") % path); - - auto info = queryPathInfo(path); - - HashAndWriteSink hashAndWriteSink(sink); - - dumpPath(path, hashAndWriteSink); - - /* Refuse to export paths that have changed. This prevents - filesystem corruption from spreading to other machines. - Don't complain if the stored hash is zero (unknown). */ - Hash hash = hashAndWriteSink.currentHash(); - if (hash != info->narHash && info->narHash != Hash(info->narHash.type)) - throw Error(format("hash of path ‘%1%’ has changed from ‘%2%’ to ‘%3%’!") % path - % printHash(info->narHash) % printHash(hash)); - - hashAndWriteSink << exportMagic << path << info->references << info->deriver; - - hashAndWriteSink << 0; // backwards compatibility -} - - -struct HashAndReadSource : Source -{ - Source & readSource; - HashSink hashSink; - bool hashing; - HashAndReadSource(Source & readSource) : readSource(readSource), hashSink(htSHA256) - { - hashing = true; - } - size_t read(unsigned char * data, size_t len) - { - size_t n = readSource.read(data, len); - if (hashing) hashSink(data, n); - return n; - } -}; - - /* Create a temporary directory in the store that won't be garbage-collected. */ Path LocalStore::createTempDirInStore() @@ -1095,103 +1066,6 @@ Path LocalStore::createTempDirInStore() } -Path LocalStore::importPath(Source & source) -{ - HashAndReadSource hashAndReadSource(source); - - /* We don't yet know what store path this archive contains (the - store path follows the archive data proper), and besides, we - don't know yet whether the signature is valid. */ - Path tmpDir = createTempDirInStore(); - AutoDelete delTmp(tmpDir); - Path unpacked = tmpDir + "/unpacked"; - - restorePath(unpacked, hashAndReadSource); - - uint32_t magic = readInt(hashAndReadSource); - if (magic != exportMagic) - throw Error("Nix archive cannot be imported; wrong format"); - - Path dstPath = readStorePath(hashAndReadSource); - - printMsg(lvlTalkative, format("importing path ‘%1%’") % dstPath); - - PathSet references = readStorePaths(hashAndReadSource); - - Path deriver = readString(hashAndReadSource); - if (deriver != "") assertStorePath(deriver); - - Hash hash = hashAndReadSource.hashSink.finish().first; - hashAndReadSource.hashing = false; - - bool haveSignature = readInt(hashAndReadSource) == 1; - - if (haveSignature) - // Ignore legacy signature. - readString(hashAndReadSource); - - /* Do the actual import. */ - - /* !!! way too much code duplication with addTextToStore() etc. */ - addTempRoot(dstPath); - - if (!isValidPath(dstPath)) { - - PathLocks outputLock; - - /* Lock the output path. But don't lock if we're being called - from a build hook (whose parent process already acquired a - lock on this path). */ - Strings locksHeld = tokenizeString(getEnv("NIX_HELD_LOCKS")); - if (find(locksHeld.begin(), locksHeld.end(), dstPath) == locksHeld.end()) - outputLock.lockPaths(singleton(dstPath)); - - if (!isValidPath(dstPath)) { - - deletePath(dstPath); - - if (rename(unpacked.c_str(), dstPath.c_str()) == -1) - throw SysError(format("cannot move ‘%1%’ to ‘%2%’") - % unpacked % dstPath); - - canonicalisePathMetaData(dstPath, -1); - - /* !!! if we were clever, we could prevent the hashPath() - here. */ - HashResult hash = hashPath(htSHA256, dstPath); - - optimisePath(dstPath); // FIXME: combine with hashPath() - - ValidPathInfo info; - info.path = dstPath; - info.narHash = hash.first; - info.narSize = hash.second; - info.references = references; - info.deriver = deriver != "" && isValidPath(deriver) ? deriver : ""; - registerValidPath(info); - } - - outputLock.setDeletion(true); - } - - return dstPath; -} - - -Paths LocalStore::importPaths(Source & source, - std::shared_ptr accessor) -{ - Paths res; - while (true) { - unsigned long long n = readLongLong(source); - if (n == 0) break; - if (n != 1) throw Error("input doesn't look like something created by ‘nix-store --export’"); - res.push_back(importPath(source)); - } - return res; -} - - void LocalStore::invalidatePathChecked(const Path & path) { assertStorePath(path); -- cgit 1.4.1