diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-05-04T11·36+0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-05-04T14·15+0200 |
commit | 538a64e8c314f23ba0c5d76201f1c20e71884a21 (patch) | |
tree | 34bdfda7346d53014619cbfa33bf1398bad4b5e2 /src/libstore/export-import.cc | |
parent | b6c768fb6a341bf1c5fe4a2d2a929415e8519b25 (diff) |
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.
Diffstat (limited to 'src/libstore/export-import.cc')
-rw-r--r-- | src/libstore/export-import.cc | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc new file mode 100644 index 000000000000..4ec01add3026 --- /dev/null +++ b/src/libstore/export-import.cc @@ -0,0 +1,136 @@ +#include "store-api.hh" +#include "archive.hh" +#include "worker-protocol.hh" + +#include <algorithm> + +namespace nix { + +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 Store::exportPaths(const Paths & paths, Sink & sink) +{ + Paths sorted = topoSortPaths(PathSet(paths.begin(), paths.end())); + std::reverse(sorted.begin(), sorted.end()); + + std::string doneLabel("paths exported"); + logger->incExpected(doneLabel, sorted.size()); + + for (auto & path : sorted) { + Activity act(*logger, lvlInfo, format("exporting path ‘%s’") % path); + sink << 1; + exportPath(path, sink); + logger->incProgress(doneLabel); + } + + sink << 0; +} + +void Store::exportPath(const Path & path, Sink & sink) +{ + auto info = queryPathInfo(path); + + HashAndWriteSink hashAndWriteSink(sink); + + narFromPath(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 << 0; +} + +struct TeeSource : Source +{ + Source & readSource; + ref<std::string> data; + TeeSource(Source & readSource) + : readSource(readSource) + , data(make_ref<std::string>()) + { + } + size_t read(unsigned char * data, size_t len) + { + size_t n = readSource.read(data, len); + this->data->append((char *) data, n); + return n; + } +}; + +struct NopSink : ParseSink +{ +}; + +Paths Store::importPaths(Source & source, std::shared_ptr<FSAccessor> 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’"); + + /* Extract the NAR from the source. */ + TeeSource tee(source); + NopSink sink; + parseDump(sink, tee); + + uint32_t magic = readInt(source); + if (magic != exportMagic) + throw Error("Nix archive cannot be imported; wrong format"); + + ValidPathInfo info; + + info.path = readStorePath(source); + + Activity act(*logger, lvlInfo, format("importing path ‘%s’") % info.path); + + info.references = readStorePaths<PathSet>(source); + + info.deriver = readString(source); + if (info.deriver != "") assertStorePath(info.deriver); + + info.narHash = hashString(htSHA256, *tee.data); + info.narSize = tee.data->size(); + + // Ignore optional legacy signature. + if (readInt(source) == 1) + readString(source); + + addToStore(info, *tee.data); + + // FIXME: implement accessors? + assert(!accessor); +#if 0 + auto accessor_ = std::dynamic_pointer_cast<BinaryCacheStoreAccessor>(accessor); + if (accessor_) + accessor_->nars.emplace(info.path, makeNarAccessor(tee.data)); +#endif + + res.push_back(info.path); + } + + return res; +} + +} |