aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/export-import.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/export-import.cc')
-rw-r--r--src/libstore/export-import.cc136
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 000000000..4ec01add3
--- /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;
+}
+
+}