2016-05-04 13:36:54 +02:00
|
|
|
#include <algorithm>
|
2020-05-19 16:54:39 +02:00
|
|
|
|
2020-05-27 22:56:34 +02:00
|
|
|
#include "libstore/store-api.hh"
|
|
|
|
#include "libstore/worker-protocol.hh"
|
|
|
|
#include "libutil/archive.hh"
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
struct HashAndWriteSink : Sink {
|
|
|
|
Sink& writeSink;
|
|
|
|
HashSink hashSink;
|
2020-05-19 23:02:23 +02:00
|
|
|
explicit HashAndWriteSink(Sink& writeSink)
|
2016-05-04 13:36:54 +02:00
|
|
|
: writeSink(writeSink), hashSink(htSHA256) {}
|
2020-05-20 05:33:07 +02:00
|
|
|
void operator()(const unsigned char* data, size_t len) override {
|
2016-05-04 13:36:54 +02:00
|
|
|
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");
|
2017-05-16 16:09:57 +02:00
|
|
|
// logger->incExpected(doneLabel, sorted.size());
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
for (auto& path : sorted) {
|
2017-07-30 13:27:57 +02:00
|
|
|
// Activity act(*logger, lvlInfo, format("exporting path '%s'") % path);
|
2016-05-04 13:36:54 +02:00
|
|
|
sink << 1;
|
|
|
|
exportPath(path, sink);
|
2017-05-16 16:09:57 +02:00
|
|
|
// logger->incProgress(doneLabel);
|
2016-05-04 13:36:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
2017-07-30 13:27:57 +02:00
|
|
|
throw Error(format("hash of path '%1%' has changed from '%2%' to '%3%'!") %
|
2017-07-04 14:47:59 +02:00
|
|
|
path % info->narHash.to_string() % hash.to_string());
|
2020-05-19 21:47:23 +02:00
|
|
|
}
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
hashAndWriteSink << exportMagic << path << info->references << info->deriver
|
|
|
|
<< 0;
|
|
|
|
}
|
|
|
|
|
2020-05-20 23:58:43 +02:00
|
|
|
Paths Store::importPaths(Source& source,
|
|
|
|
const std::shared_ptr<FSAccessor>& accessor,
|
2017-06-28 18:11:01 +02:00
|
|
|
CheckSigsFlag checkSigs) {
|
2016-05-04 13:36:54 +02:00
|
|
|
Paths res;
|
|
|
|
while (true) {
|
2017-03-01 13:52:54 +01:00
|
|
|
auto n = readNum<uint64_t>(source);
|
2016-05-04 13:36:54 +02:00
|
|
|
if (n == 0) {
|
|
|
|
break;
|
2020-05-19 19:55:58 +02:00
|
|
|
}
|
2017-07-30 13:27:57 +02:00
|
|
|
if (n != 1) {
|
|
|
|
throw Error(
|
|
|
|
"input doesn't look like something created by 'nix-store --export'");
|
2020-05-19 21:47:23 +02:00
|
|
|
}
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
/* Extract the NAR from the source. */
|
2017-03-01 16:16:04 +01:00
|
|
|
TeeSink tee(source);
|
|
|
|
parseDump(tee, tee.source);
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
uint32_t magic = readInt(source);
|
|
|
|
if (magic != exportMagic) {
|
|
|
|
throw Error("Nix archive cannot be imported; wrong format");
|
2020-05-19 21:47:23 +02:00
|
|
|
}
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
ValidPathInfo info;
|
|
|
|
|
2016-06-01 14:49:12 +02:00
|
|
|
info.path = readStorePath(*this, source);
|
2016-05-04 13:36:54 +02:00
|
|
|
|
2017-07-30 13:27:57 +02:00
|
|
|
// Activity act(*logger, lvlInfo, format("importing path '%s'") %
|
|
|
|
// info.path);
|
2016-05-04 13:36:54 +02:00
|
|
|
|
2016-06-01 14:49:12 +02:00
|
|
|
info.references = readStorePaths<PathSet>(*this, source);
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
info.deriver = readString(source);
|
2020-05-20 23:27:37 +02:00
|
|
|
if (!info.deriver.empty()) {
|
2016-05-04 13:36:54 +02:00
|
|
|
assertStorePath(info.deriver);
|
2020-05-19 19:55:58 +02:00
|
|
|
}
|
2016-05-04 13:36:54 +02:00
|
|
|
|
2017-03-01 16:16:04 +01:00
|
|
|
info.narHash = hashString(htSHA256, *tee.source.data);
|
|
|
|
info.narSize = tee.source.data->size();
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
// Ignore optional legacy signature.
|
|
|
|
if (readInt(source) == 1) {
|
|
|
|
readString(source);
|
2020-05-19 19:55:58 +02:00
|
|
|
}
|
2016-05-04 13:36:54 +02:00
|
|
|
|
2017-06-28 18:11:01 +02:00
|
|
|
addToStore(info, tee.source.data, NoRepair, checkSigs, accessor);
|
2016-05-04 13:36:54 +02:00
|
|
|
|
|
|
|
res.push_back(info.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace nix
|