diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh index de6941561d5e361d78de581cdf8fdf483faa5d57..0020f89eee49dcbe9a62d3944f08c338eecdc231 100644 --- a/src/libstore/binary-cache-store.hh +++ b/src/libstore/binary-cache-store.hh @@ -170,6 +170,9 @@ public: ref<FSAccessor> getFSAccessor() override; + void addSignatures(const Path & storePath, const StringSet & sigs) + { notImpl(); } + }; } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 9b961b1924a6c21a987a2a91e0e0bf95de8bed25..28e340af7a5e8132372b255621373e34004082c0 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -312,7 +312,7 @@ void LocalStore::openDB(bool create) stmtRegisterValidPath.create(db, "insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate) values (?, ?, ?, ?, ?, ?);"); stmtUpdatePathInfo.create(db, - "update ValidPaths set narSize = ?, hash = ?, ultimate = ? where path = ?;"); + "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ? where path = ?;"); stmtAddReference.create(db, "insert or replace into Refs (referrer, reference) values (?, ?);"); stmtQueryPathInfo.create(db, @@ -683,14 +683,14 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path) } -/* Update path info in the database. Currently only updates the - narSize field. */ +/* Update path info in the database. */ void LocalStore::updatePathInfo(const ValidPathInfo & info) { stmtUpdatePathInfo.use() (info.narSize, info.narSize != 0) ("sha256:" + printHash(info.narHash)) (info.ultimate ? 1 : 0, info.ultimate) + (concatStringsSep(" ", info.sigs), !info.sigs.empty()) (info.path) .exec(); } @@ -1694,4 +1694,20 @@ void LocalStore::vacuumDB() } +void LocalStore::addSignatures(const Path & storePath, const StringSet & sigs) +{ + retrySQLite<void>([&]() { + SQLiteTxn txn(db); + + auto info = queryPathInfo(storePath); + + info.sigs.insert(sigs.begin(), sigs.end()); + + updatePathInfo(info); + + txn.commit(); + }); +} + + } diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index e90894277e923826dbe4c84f51419c854f1f46e5..ec8146e68b79e59e58e0eec579cb702c1a0b3338 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -182,6 +182,8 @@ public: void setSubstituterEnv(); + void addSignatures(const Path & storePath, const StringSet & sigs) override; + private: Path schemaPath; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 7893f2a4c3ccbda407b130b60deea8c5fe340696..4d5d689dc7f96934733599add4d1d37068b46397 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -554,6 +554,15 @@ bool RemoteStore::verifyStore(bool checkContents, bool repair) } +void RemoteStore::addSignatures(const Path & storePath, const StringSet & sigs) +{ + auto conn(connections->get()); + conn->to << wopAddSignatures << storePath << sigs; + conn->processStderr(); + readInt(conn->from); +} + + RemoteStore::Connection::~Connection() { try { diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 85c8292c7698349e286e7e89cf59e02106f77bc6..cede4d332f8896f68693f884193bdddccc2c1478 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -93,6 +93,8 @@ public: bool verifyStore(bool checkContents, bool repair) override; + void addSignatures(const Path & storePath, const StringSet & sigs) override; + private: struct Connection diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 7c6e4c0795eda9072f1b5b9593972804a89c5c3d..4ea360b9d17a35c33fd096d97a56395e4ee94865 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -346,6 +346,10 @@ public: /* Return an object to access files in the Nix store. */ virtual ref<FSAccessor> getFSAccessor() = 0; + /* Add signatures to the specified store path. The signatures are + not verified. */ + virtual void addSignatures(const Path & storePath, const StringSet & sigs) = 0; + /* Utility functions. */ /* Read a derivation, after ensuring its existence through diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index 4f60c3adcf5f9d700629b665ae4cd2060b60cb48..c10598d5d301128433bb800ab15ea12834e79631 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -45,6 +45,7 @@ typedef enum { wopOptimiseStore = 34, wopVerifyStore = 35, wopBuildDerivation = 36, + wopAddSignatures = 37, } WorkerOp; diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index 527f6bca93ac9e2013e6ab54a47b164cd883b59d..439cd3dc0bcea87b5f723e9ea8b221139179d336 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -543,6 +543,18 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe break; } + case wopAddSignatures: { + Path path = readStorePath(from); + StringSet sigs = readStrings<StringSet>(from); + startWork(); + if (!trusted) + throw Error("you are not privileged to add signatures"); + store->addSignatures(path, sigs); + stopWork(); + to << 1; + break; + } + default: throw Error(format("invalid operation %1%") % op); } diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc new file mode 100644 index 0000000000000000000000000000000000000000..e3544a1fd0b60612c4aa704c2bd66a447047c2b9 --- /dev/null +++ b/src/nix/sigs.cc @@ -0,0 +1,133 @@ +#include "affinity.hh" // FIXME +#include "command.hh" +#include "progress-bar.hh" +#include "shared.hh" +#include "store-api.hh" +#include "thread-pool.hh" + +#include <atomic> + +using namespace nix; + +struct CmdCopySigs : StorePathsCommand +{ + Strings substituterUris; + + CmdCopySigs() + { + mkFlag('s', "substituter", {"store-uri"}, "use signatures from specified store", 1, + [&](Strings ss) { substituterUris.push_back(ss.front()); }); + } + + std::string name() override + { + return "copy-sigs"; + } + + std::string description() override + { + return "copy path signatures from substituters (like binary caches)"; + } + + void run(ref<Store> store, Paths storePaths) override + { + restoreAffinity(); // FIXME + + if (substituterUris.empty()) + throw UsageError("you must specify at least one subtituter using ‘-s’"); + + // FIXME: factor out commonality with MixVerify. + std::vector<ref<Store>> substituters; + for (auto & s : substituterUris) + substituters.push_back(openStoreAt(s)); + + ProgressBar progressBar; + + ThreadPool pool; + + std::atomic<size_t> done{0}; + std::atomic<size_t> added{0}; + + auto showProgress = [&]() { + return (format("[%d/%d done]") % done % storePaths.size()).str(); + }; + + progressBar.updateStatus(showProgress()); + + auto doPath = [&](const Path & storePath) { + auto activity(progressBar.startActivity(format("getting signatures for ‘%s’") % storePath)); + + checkInterrupt(); + + auto info = store->queryPathInfo(storePath); + + StringSet newSigs; + + for (auto & store2 : substituters) { + if (!store2->isValidPath(storePath)) continue; + auto info2 = store2->queryPathInfo(storePath); + + /* Don't import signatures that don't match this + binary. */ + if (info.narHash != info2.narHash || + info.narSize != info2.narSize || + info.references != info2.references) + continue; + + for (auto & sig : info2.sigs) + if (!info.sigs.count(sig)) + newSigs.insert(sig); + } + + if (!newSigs.empty()) { + store->addSignatures(storePath, newSigs); + added += newSigs.size(); + } + + done++; + progressBar.updateStatus(showProgress()); + }; + + for (auto & storePath : storePaths) + pool.enqueue(std::bind(doPath, storePath)); + + pool.process(); + + progressBar.done(); + + printMsg(lvlInfo, format("imported %d signatures") % added); + } +}; + +static RegisterCommand r1(make_ref<CmdCopySigs>()); + +struct CmdQueryPathSigs : StorePathsCommand +{ + CmdQueryPathSigs() + { + } + + std::string name() override + { + return "query-path-sigs"; + } + + std::string description() override + { + return "print store path signatures"; + } + + void run(ref<Store> store, Paths storePaths) override + { + for (auto & storePath : storePaths) { + auto info = store->queryPathInfo(storePath); + std::cout << storePath << " "; + if (info.ultimate) std::cout << "ultimate "; + for (auto & sig : info.sigs) + std::cout << sig << " "; + std::cout << "\n"; + } + } +}; + +static RegisterCommand r2(make_ref<CmdQueryPathSigs>());