aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstore/binary-cache-store.cc3
-rw-r--r--src/libstore/build.cc14
-rw-r--r--src/libstore/daemon.cc10
-rw-r--r--src/libstore/export-import.cc4
-rw-r--r--src/libstore/legacy-ssh-store.cc7
-rw-r--r--src/libstore/local-store.cc21
-rw-r--r--src/libstore/misc.cc5
-rw-r--r--src/libstore/nar-info-disk-cache.cc2
-rw-r--r--src/libstore/nar-info.cc3
-rw-r--r--src/libstore/nar-info.hh2
-rw-r--r--src/libstore/path-info.hh157
-rw-r--r--src/libstore/remote-store.cc15
-rw-r--r--src/libstore/store-api.cc29
-rw-r--r--src/libstore/store-api.hh90
-rw-r--r--src/nix-store/dotgraph.cc2
-rw-r--r--src/nix-store/graphml.cc2
-rw-r--r--src/nix-store/nix-store.cc8
-rw-r--r--src/nix/make-content-addressable.cc2
-rw-r--r--src/nix/sigs.cc3
19 files changed, 229 insertions, 150 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 30150eeba..063c88965 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -194,8 +194,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource
reads, but typically they'll already be cached. */
for (auto & ref : info.references)
try {
- if (ref != info.path)
- queryPathInfo(ref);
+ queryPathInfo(ref);
} catch (InvalidPath &) {
throw Error("cannot add '%s' to the binary cache because the reference '%s' is not valid",
printStorePath(info.path), printStorePath(ref));
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 4156cd678..7134c3994 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -3843,7 +3843,7 @@ void DerivationGoal::registerOutputs()
ValidPathInfo info(worker.store.parseStorePath(path));
info.narHash = hash.first;
info.narSize = hash.second;
- info.references = std::move(references);
+ info.setReferencesPossiblyToSelf(std::move(references));
info.deriver = drvPath;
info.ultimate = true;
info.ca = ca;
@@ -3972,12 +3972,12 @@ void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
auto i = outputsByPath.find(worker.store.printStorePath(path));
if (i != outputsByPath.end()) {
closureSize += i->second.narSize;
- for (auto & ref : i->second.references)
+ for (auto & ref : i->second.referencesPossiblyToSelf())
pathsLeft.push(ref);
} else {
auto info = worker.store.queryPathInfo(path);
closureSize += info->narSize;
- for (auto & ref : info->references)
+ for (auto & ref : info->referencesPossiblyToSelf())
pathsLeft.push(ref);
}
}
@@ -4006,7 +4006,7 @@ void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
auto used = recursive
? getClosure(info.path).first
- : info.references;
+ : info.referencesPossiblyToSelf();
if (recursive && checks.ignoreSelfRefs)
used.erase(info.path);
@@ -4500,8 +4500,7 @@ void SubstitutionGoal::tryNext()
/* To maintain the closure invariant, we first have to realise the
paths referenced by this one. */
for (auto & i : info->references)
- if (i != storePath) /* ignore self-references */
- addWaitee(worker.makeSubstitutionGoal(i));
+ addWaitee(worker.makeSubstitutionGoal(i));
if (waitees.empty()) /* to prevent hang (no wake-up event) */
referencesValid();
@@ -4521,8 +4520,7 @@ void SubstitutionGoal::referencesValid()
}
for (auto & i : info->references)
- if (i != storePath) /* ignore self-references */
- assert(worker.store.isValidPath(i));
+ assert(worker.store.isValidPath(i));
state = &SubstitutionGoal::tryToRun;
worker.wakeUp(shared_from_this());
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index b9a750425..53202f8d1 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -301,7 +301,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork();
StorePathSet paths;
if (op == wopQueryReferences)
- for (auto & i : store->queryPathInfo(path)->references)
+ for (auto & i : store->queryPathInfo(path)->referencesPossiblyToSelf())
paths.insert(i);
else if (op == wopQueryReferrers)
store->queryReferrers(path, paths);
@@ -587,7 +587,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
else {
to << 1
<< (i->second.deriver ? store->printStorePath(*i->second.deriver) : "");
- writeStorePaths(*store, to, i->second.references);
+ writeStorePaths(*store, to, i->second.referencesPossiblyToSelf(path));
to << i->second.downloadSize
<< i->second.narSize;
}
@@ -610,7 +610,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
for (auto & i : infos) {
to << store->printStorePath(i.first)
<< (i.second.deriver ? store->printStorePath(*i.second.deriver) : "");
- writeStorePaths(*store, to, i.second.references);
+ writeStorePaths(*store, to, i.second.referencesPossiblyToSelf(i.first));
to << i.second.downloadSize << i.second.narSize;
}
break;
@@ -639,7 +639,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
to << 1;
to << (info->deriver ? store->printStorePath(*info->deriver) : "")
<< info->narHash->to_string(Base16, false);
- writeStorePaths(*store, to, info->references);
+ writeStorePaths(*store, to, info->referencesPossiblyToSelf());
to << info->registrationTime << info->narSize;
if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
to << info->ultimate
@@ -699,7 +699,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
if (deriver != "")
info.deriver = store->parseStorePath(deriver);
info.narHash = Hash(readString(from), htSHA256);
- info.references = readStorePaths<StorePathSet>(*store, from);
+ info.setReferencesPossiblyToSelf(readStorePaths<StorePathSet>(*store, from));
from >> info.registrationTime >> info.narSize >> info.ultimate;
info.sigs = readStrings<StringSet>(from);
info.ca = parseContentAddressOpt(readString(from));
diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc
index a0fc22264..22ab38233 100644
--- a/src/libstore/export-import.cc
+++ b/src/libstore/export-import.cc
@@ -45,7 +45,7 @@ void Store::exportPath(const StorePath & path, Sink & sink)
teeSink
<< exportMagic
<< printStorePath(path);
- writeStorePaths(*this, teeSink, info->references);
+ writeStorePaths(*this, teeSink, info->referencesPossiblyToSelf());
teeSink
<< (info->deriver ? printStorePath(*info->deriver) : "")
<< 0;
@@ -73,7 +73,7 @@ StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs)
//Activity act(*logger, lvlInfo, format("importing path '%s'") % info.path);
- info.references = readStorePaths<StorePathSet>(*this, source);
+ info.setReferencesPossiblyToSelf(readStorePaths<StorePathSet>(*this, source));
auto deriver = readString(source);
if (deriver != "")
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index 5d7566121..9745a4466 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -103,11 +103,10 @@ struct LegacySSHStore : public Store
auto info = std::make_shared<ValidPathInfo>(parseStorePath(p));
assert(path == info->path);
- PathSet references;
auto deriver = readString(conn->from);
if (deriver != "")
info->deriver = parseStorePath(deriver);
- info->references = readStorePaths<StorePathSet>(*this, conn->from);
+ info->setReferencesPossiblyToSelf(readStorePaths<StorePathSet>(*this, conn->from));
readLongLong(conn->from); // download size
info->narSize = readLongLong(conn->from);
@@ -139,7 +138,7 @@ struct LegacySSHStore : public Store
<< printStorePath(info.path)
<< (info.deriver ? printStorePath(*info.deriver) : "")
<< info.narHash->to_string(Base16, false);
- writeStorePaths(*this, conn->to, info.references);
+ writeStorePaths(*this, conn->to, info.referencesPossiblyToSelf());
conn->to
<< info.registrationTime
<< info.narSize
@@ -168,7 +167,7 @@ struct LegacySSHStore : public Store
conn->to
<< exportMagic
<< printStorePath(info.path);
- writeStorePaths(*this, conn->to, info.references);
+ writeStorePaths(*this, conn->to, info.referencesPossiblyToSelf());
conn->to
<< (info.deriver ? printStorePath(*info.deriver) : "")
<< 0
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index f6ce8877e..4b7b08b21 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -664,8 +664,10 @@ void LocalStore::queryPathInfoUncached(const StorePath & path,
/* Get the references. */
auto useQueryReferences(state->stmtQueryReferences.use()(info->id));
- while (useQueryReferences.next())
- info->references.insert(parseStorePath(useQueryReferences.getStr(0)));
+ while (useQueryReferences.next()) {
+ info->insertReferencePossiblyToSelf(
+ parseStorePath(useQueryReferences.getStr(0)));
+ }
return info;
}));
@@ -865,10 +867,12 @@ void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, Subst
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
std::shared_ptr<const ValidPathInfo>(info));
infos.insert_or_assign(path.first, SubstitutablePathInfo{
- info->deriver,
info->references,
+ info->hasSelfReference,
+ info->deriver,
narInfo ? narInfo->fileSize : 0,
- info->narSize});
+ info->narSize,
+ });
} catch (InvalidPath &) {
} catch (SubstituterDisabled &) {
} catch (Error & e) {
@@ -915,7 +919,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
for (auto & i : infos) {
auto referrer = queryValidPathId(*state, i.path);
- for (auto & j : i.references)
+ for (auto & j : i.referencesPossiblyToSelf())
state->stmtAddReference.use()(referrer)(queryValidPathId(*state, j)).exec();
}
@@ -994,14 +998,13 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
deletePath(realPath);
// text hashing has long been allowed to have non-self-references because it is used for drv files.
- bool refersToSelf = info.references.count(info.path) > 0;
- if (info.ca.has_value() && !info.references.empty() && !(std::holds_alternative<TextHash>(*info.ca) && !refersToSelf))
+ if (info.ca.has_value() && !info.references.empty() && !(std::holds_alternative<TextHash>(*info.ca) && info.hasSelfReference))
settings.requireExperimentalFeature("ca-references");
/* While restoring the path from the NAR, compute the hash
of the NAR. */
std::unique_ptr<AbstractHashSink> hashSink;
- if (!info.ca.has_value() || !info.references.count(info.path))
+ if (!info.ca.has_value() || !info.hasSelfReference)
hashSink = std::make_unique<HashSink>(htSHA256);
else
hashSink = std::make_unique<HashModuloSink>(htSHA256, std::string(info.path.hashPart()));
@@ -1313,7 +1316,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
printMsg(lvlTalkative, "checking contents of '%s'", printStorePath(i));
std::unique_ptr<AbstractHashSink> hashSink;
- if (!info->ca || !info->references.count(info->path))
+ if (!info->ca || !info->hasSelfReference)
hashSink = std::make_unique<HashSink>(info->narHash->type);
else
hashSink = std::make_unique<HashModuloSink>(info->narHash->type, std::string(info->path.hashPart()));
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index 7f1b62f26..799ee78cc 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -61,8 +61,7 @@ void Store::computeFSClosure(const StorePathSet & startPaths,
} else {
for (auto & ref : info->references)
- if (ref != path)
- enqueue(printStorePath(ref));
+ enqueue(printStorePath(ref));
if (includeOutputs && path.isDerivation())
for (auto & i : queryDerivationOutputs(path))
@@ -278,7 +277,7 @@ StorePaths Store::topoSortPaths(const StorePathSet & paths)
for (auto & i : references)
/* Don't traverse into paths that don't exist. That can
happen due to substitutes for non-existent paths. */
- if (i != path && paths.count(i))
+ if (paths.count(i))
dfsVisit(i, &path);
sorted.push_back(path);
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index 9ddb9957f..523cf7c69 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -198,7 +198,7 @@ public:
narInfo->narHash = Hash(queryNAR.getStr(6));
narInfo->narSize = queryNAR.getInt(7);
for (auto & r : tokenizeString<Strings>(queryNAR.getStr(8), " "))
- narInfo->references.insert(StorePath(r));
+ narInfo->insertReferencePossiblyToSelf(StorePath(r));
if (!queryNAR.isNull(9))
narInfo->deriver = StorePath(queryNAR.getStr(9));
for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(10), " "))
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index ca471463c..aaeeea6ff 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -1,5 +1,6 @@
#include "globals.hh"
#include "nar-info.hh"
+#include "store-api.hh"
namespace nix {
@@ -55,7 +56,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
auto refs = tokenizeString<Strings>(value, " ");
if (!references.empty()) throw corrupt();
for (auto & r : refs)
- references.insert(StorePath(r));
+ insertReferencePossiblyToSelf(StorePath(r));
}
else if (name == "Deriver") {
if (value != "unknown-deriver")
diff --git a/src/libstore/nar-info.hh b/src/libstore/nar-info.hh
index eff19f0ef..58235a7fc 100644
--- a/src/libstore/nar-info.hh
+++ b/src/libstore/nar-info.hh
@@ -2,7 +2,7 @@
#include "types.hh"
#include "hash.hh"
-#include "store-api.hh"
+#include "path-info.hh"
namespace nix {
diff --git a/src/libstore/path-info.hh b/src/libstore/path-info.hh
new file mode 100644
index 000000000..5ebe9e8d9
--- /dev/null
+++ b/src/libstore/path-info.hh
@@ -0,0 +1,157 @@
+#pragma once
+
+// TODO many of thes eare not needed.
+#include "path.hh"
+#include "hash.hh"
+#include "content-address.hh"
+#include "serialise.hh"
+#include "crypto.hh"
+#include "lru-cache.hh"
+#include "sync.hh"
+#include "globals.hh"
+#include "config.hh"
+
+#include <limits>
+#include <string>
+#include <optional>
+
+namespace nix {
+
+
+class Store;
+
+template<typename Ref>
+struct PathReferences
+{
+ std::set<Ref> references;
+ bool hasSelfReference = false;
+
+ /* Functions to view references + hasSelfReference as one set, mainly for
+ compatibility's sake. */
+ StorePathSet referencesPossiblyToSelf(const Ref & self) const;
+ void insertReferencePossiblyToSelf(const Ref & self, Ref && ref);
+ void setReferencesPossiblyToSelf(const Ref & self, std::set<Ref> && refs);
+};
+
+template<typename Ref>
+StorePathSet PathReferences<Ref>::referencesPossiblyToSelf(const Ref & self) const
+{
+ StorePathSet refs { references };
+ if (hasSelfReference)
+ refs.insert(self);
+ return refs;
+}
+
+template<typename Ref>
+void PathReferences<Ref>::insertReferencePossiblyToSelf(const Ref & self, Ref && ref)
+{
+ if (ref == self)
+ hasSelfReference = true;
+ else
+ references.insert(std::move(ref));
+}
+
+template<typename Ref>
+void PathReferences<Ref>::setReferencesPossiblyToSelf(const Ref & self, std::set<Ref> && refs)
+{
+ if (refs.count(self))
+ hasSelfReference = true;
+ refs.erase(self);
+
+ references = refs;
+}
+
+struct ValidPathInfo : PathReferences<StorePath>
+{
+ StorePath path;
+ std::optional<StorePath> deriver;
+ // TODO document this
+ std::optional<Hash> narHash;
+ time_t registrationTime = 0;
+ uint64_t narSize = 0; // 0 = unknown
+ uint64_t id; // internal use only
+
+ /* Whether the path is ultimately trusted, that is, it's a
+ derivation output that was built locally. */
+ bool ultimate = false;
+
+ StringSet sigs; // note: not necessarily verified
+
+ /* If non-empty, an assertion that the path is content-addressed,
+ i.e., that the store path is computed from a cryptographic hash
+ of the contents of the path, plus some other bits of data like
+ the "name" part of the path. Such a path doesn't need
+ signatures, since we don't have to trust anybody's claim that
+ the path is the output of a particular derivation. (In the
+ extensional store model, we have to trust that the *contents*
+ of an output path of a derivation were actually produced by
+ that derivation. In the intensional model, we have to trust
+ that a particular output path was produced by a derivation; the
+ path then implies the contents.)
+
+ Ideally, the content-addressability assertion would just be a Boolean,
+ and the store path would be computed from the name component, ‘narHash’
+ and ‘references’. However, we support many types of content addresses.
+ */
+ std::optional<ContentAddress> ca;
+
+ bool operator == (const ValidPathInfo & i) const
+ {
+ return
+ path == i.path
+ && narHash == i.narHash
+ && hasSelfReference == i.hasSelfReference
+ && references == i.references;
+ }
+
+ /* Return a fingerprint of the store path to be used in binary
+ cache signatures. It contains the store path, the base-32
+ SHA-256 hash of the NAR serialisation of the path, the size of
+ the NAR, and the sorted references. The size field is strictly
+ speaking superfluous, but might prevent endless/excessive data
+ attacks. */
+ std::string fingerprint(const Store & store) const;
+
+ void sign(const Store & store, const SecretKey & secretKey);
+
+ /* Return true iff the path is verifiably content-addressed. */
+ bool isContentAddressed(const Store & store) const;
+
+ /* Functions to view references + hasSelfReference as one set, mainly for
+ compatibility's sake. */
+ StorePathSet referencesPossiblyToSelf() const;
+ void insertReferencePossiblyToSelf(StorePath && ref);
+ void setReferencesPossiblyToSelf(StorePathSet && refs);
+
+ static const size_t maxSigs = std::numeric_limits<size_t>::max();
+
+ /* Return the number of signatures on this .narinfo that were
+ produced by one of the specified keys, or maxSigs if the path
+ is content-addressed. */
+ size_t checkSignatures(const Store & store, const PublicKeys & publicKeys) const;
+
+ /* Verify a single signature. */
+ bool checkSignature(const Store & store, const PublicKeys & publicKeys, const std::string & sig) const;
+
+ Strings shortRefs() const;
+
+ ValidPathInfo(const ValidPathInfo & other) = default;
+
+ ValidPathInfo(StorePath && path) : path(std::move(path)) { };
+ ValidPathInfo(const StorePath & path) : path(path) { };
+
+ virtual ~ValidPathInfo() { }
+};
+
+typedef list<ValidPathInfo> ValidPathInfos;
+
+
+struct SubstitutablePathInfo : PathReferences<StorePath>
+{
+ std::optional<StorePath> deriver;
+ uint64_t downloadSize; /* 0 = unknown or inapplicable */
+ uint64_t narSize; /* 0 = unknown */
+};
+
+typedef std::map<StorePath, SubstitutablePathInfo> SubstitutablePathInfos;
+}
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 0c65bcd29..d7aef3ea5 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -367,7 +367,7 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
auto deriver = readString(conn->from);
if (deriver != "")
info.deriver = parseStorePath(deriver);
- info.references = readStorePaths<StorePathSet>(*this, conn->from);
+ info.setReferencesPossiblyToSelf(i.first, readStorePaths<StorePathSet>(*this, conn->from));
info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from);
infos.insert_or_assign(i.first, std::move(info));
@@ -386,11 +386,12 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S
conn.processStderr();
size_t count = readNum<size_t>(conn->from);
for (size_t n = 0; n < count; n++) {
- SubstitutablePathInfo & info(infos[parseStorePath(readString(conn->from))]);
+ auto path = parseStorePath(readString(conn->from));
+ SubstitutablePathInfo & info { infos[path] };
auto deriver = readString(conn->from);
if (deriver != "")
info.deriver = parseStorePath(deriver);
- info.references = readStorePaths<StorePathSet>(*this, conn->from);
+ info.setReferencesPossiblyToSelf(path, readStorePaths<StorePathSet>(*this, conn->from));
info.downloadSize = readLongLong(conn->from);
info.narSize = readLongLong(conn->from);
}
@@ -423,7 +424,7 @@ void RemoteStore::queryPathInfoUncached(const StorePath & path,
auto deriver = readString(conn->from);
if (deriver != "") info->deriver = parseStorePath(deriver);
info->narHash = Hash(readString(conn->from), htSHA256);
- info->references = readStorePaths<StorePathSet>(*this, conn->from);
+ info->setReferencesPossiblyToSelf(readStorePaths<StorePathSet>(*this, conn->from));
conn->from >> info->registrationTime >> info->narSize;
if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) {
conn->from >> info->ultimate;
@@ -503,7 +504,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
sink
<< exportMagic
<< printStorePath(info.path);
- writeStorePaths(*this, sink, info.references);
+ writeStorePaths(*this, sink, info.referencesPossiblyToSelf());
sink
<< (info.deriver ? printStorePath(*info.deriver) : "")
<< 0 // == no legacy signature
@@ -514,7 +515,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
conn.processStderr(0, source2.get());
auto importedPaths = readStorePaths<StorePathSet>(*this, conn->from);
- assert(importedPaths.size() <= 1);
+ assert(importedPaths.empty() == 0); // doesn't include possible self reference
}
else {
@@ -522,7 +523,7 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source,
<< printStorePath(info.path)
<< (info.deriver ? printStorePath(*info.deriver) : "")
<< info.narHash->to_string(Base16, false);
- writeStorePaths(*this, conn->to, info.references);
+ writeStorePaths(*this, conn->to, info.referencesPossiblyToSelf());
conn->to << info.registrationTime << info.narSize
<< info.ultimate << info.sigs << renderContentAddress(info.ca)
<< repair << !checkSigs;
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 33f931442..62feb388a 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -874,7 +874,7 @@ std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istre
if (!string2Int(s, n)) throw Error("number expected");
while (n--) {
getline(str, s);
- info.references.insert(store.parseStorePath(s));
+ info.insertReferencePossiblyToSelf(store.parseStorePath(s));
}
if (!str || str.eof()) throw Error("missing input");
return std::optional<ValidPathInfo>(std::move(info));
@@ -897,6 +897,20 @@ string showPaths(const PathSet & paths)
return concatStringsSep(", ", quoteStrings(paths));
}
+StorePathSet ValidPathInfo::referencesPossiblyToSelf() const
+{
+ return PathReferences<StorePath>::referencesPossiblyToSelf(path);
+}
+
+void ValidPathInfo::insertReferencePossiblyToSelf(StorePath && ref)
+{
+ return PathReferences<StorePath>::insertReferencePossiblyToSelf(path, std::move(ref));
+}
+
+void ValidPathInfo::setReferencesPossiblyToSelf(StorePathSet && refs)
+{
+ return PathReferences<StorePath>::setReferencesPossiblyToSelf(path, std::move(refs));
+}
std::string ValidPathInfo::fingerprint(const Store & store) const
{
@@ -907,7 +921,7 @@ std::string ValidPathInfo::fingerprint(const Store & store) const
"1;" + store.printStorePath(path) + ";"
+ narHash->to_string(Base32, true) + ";"
+ std::to_string(narSize) + ";"
- + concatStringsSep(",", store.printStorePathSet(references));
+ + concatStringsSep(",", store.printStorePathSet(referencesPossiblyToSelf()));
}
@@ -922,16 +936,11 @@ bool ValidPathInfo::isContentAddressed(const Store & store) const
auto caPath = std::visit(overloaded {
[&](TextHash th) {
+ assert(!hasSelfReference);
return store.makeTextPath(path.name(), th.hash, references);
},
[&](FixedOutputHash fsh) {
- auto refs = references;
- bool hasSelfReference = false;
- if (refs.count(path)) {
- hasSelfReference = true;
- refs.erase(path);
- }
- return store.makeFixedOutputPath(fsh.method, fsh.hash, path.name(), refs, hasSelfReference);
+ return store.makeFixedOutputPath(fsh.method, fsh.hash, path.name(), references, hasSelfReference);
}
}, *ca);
@@ -965,7 +974,7 @@ bool ValidPathInfo::checkSignature(const Store & store, const PublicKeys & publi
Strings ValidPathInfo::shortRefs() const
{
Strings refs;
- for (auto & r : references)
+ for (auto & r : referencesPossiblyToSelf())
refs.push_back(std::string(r.to_string()));
return refs;
}
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 49da19496..a2856388d 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -10,6 +10,7 @@
#include "globals.hh"
#include "config.hh"
#include "derivations.hh"
+#include "path-info.hh"
#include <atomic>
#include <limits>
@@ -101,95 +102,6 @@ struct GCResults
};
-struct SubstitutablePathInfo
-{
- std::optional<StorePath> deriver;
- StorePathSet references;
- uint64_t downloadSize; /* 0 = unknown or inapplicable */
- uint64_t narSize; /* 0 = unknown */
-};
-
-typedef std::map<StorePath, SubstitutablePathInfo> SubstitutablePathInfos;
-
-struct ValidPathInfo
-{
- StorePath path;
- std::optional<StorePath> deriver;
- // TODO document this
- std::optional<Hash> narHash;
- StorePathSet references;
- time_t registrationTime = 0;
- uint64_t narSize = 0; // 0 = unknown
- uint64_t id; // internal use only
-
- /* Whether the path is ultimately trusted, that is, it's a
- derivation output that was built locally. */
- bool ultimate = false;
-
- StringSet sigs; // note: not necessarily verified
-
- /* If non-empty, an assertion that the path is content-addressed,
- i.e., that the store path is computed from a cryptographic hash
- of the contents of the path, plus some other bits of data like
- the "name" part of the path. Such a path doesn't need
- signatures, since we don't have to trust anybody's claim that
- the path is the output of a particular derivation. (In the
- extensional store model, we have to trust that the *contents*
- of an output path of a derivation were actually produced by
- that derivation. In the intensional model, we have to trust
- that a particular output path was produced by a derivation; the
- path then implies the contents.)
-
- Ideally, the content-addressability assertion would just be a Boolean,
- and the store path would be computed from the name component, ‘narHash’
- and ‘references’. However, we support many types of content addresses.
- */
- std::optional<ContentAddress> ca;
-
- bool operator == (const ValidPathInfo & i) const
- {
- return
- path == i.path
- && narHash == i.narHash
- && references == i.references;
- }
-
- /* Return a fingerprint of the store path to be used in binary
- cache signatures. It contains the store path, the base-32
- SHA-256 hash of the NAR serialisation of the path, the size of
- the NAR, and the sorted references. The size field is strictly
- speaking superfluous, but might prevent endless/excessive data
- attacks. */
- std::string fingerprint(const Store & store) const;
-
- void sign(const Store & store, const SecretKey & secretKey);
-
- /* Return true iff the path is verifiably content-addressed. */
- bool isContentAddressed(const Store & store) const;
-
- static const size_t maxSigs = std::numeric_limits<size_t>::max();
-
- /* Return the number of signatures on this .narinfo that were
- produced by one of the specified keys, or maxSigs if the path
- is content-addressed. */
- size_t checkSignatures(const Store & store, const PublicKeys & publicKeys) const;
-
- /* Verify a single signature. */
- bool checkSignature(const Store & store, const PublicKeys & publicKeys, const std::string & sig) const;
-
- Strings shortRefs() const;
-
- ValidPathInfo(const ValidPathInfo & other) = default;
-
- ValidPathInfo(StorePath && path) : path(std::move(path)) { };
- ValidPathInfo(const StorePath & path) : path(path) { };
-
- virtual ~ValidPathInfo() { }
-};
-
-typedef list<ValidPathInfo> ValidPathInfos;
-
-
enum BuildMode { bmNormal, bmRepair, bmCheck };
diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc
index 8b699f39b..45abe0405 100644
--- a/src/nix-store/dotgraph.cc
+++ b/src/nix-store/dotgraph.cc
@@ -58,7 +58,7 @@ void printDotGraph(ref<Store> store, StorePathSet && roots)
cout << makeNode(std::string(path.to_string()), path.name(), "#ff0000");
- for (auto & p : store->queryPathInfo(path)->references) {
+ for (auto & p : store->queryPathInfo(path)->referencesPossiblyToSelf()) {
if (p != path) {
workList.insert(p);
cout << makeEdge(std::string(p.to_string()), std::string(path.to_string()));
diff --git a/src/nix-store/graphml.cc b/src/nix-store/graphml.cc
index 8ca5c9c8d..1cd974e41 100644
--- a/src/nix-store/graphml.cc
+++ b/src/nix-store/graphml.cc
@@ -71,7 +71,7 @@ void printGraphML(ref<Store> store, StorePathSet && roots)
auto info = store->queryPathInfo(path);
cout << makeNode(*info);
- for (auto & p : info->references) {
+ for (auto & p : info->referencesPossiblyToSelf()) {
if (p != path) {
workList.insert(p);
cout << makeEdge(path.to_string(), p.to_string());
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 7b26970ef..8fdf587e4 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -245,7 +245,7 @@ static void printTree(const StorePath & path,
closure(B). That is, if derivation A is an (possibly indirect)
input of B, then A is printed first. This has the effect of
flattening the tree, preventing deeply nested structures. */
- auto sorted = store->topoSortPaths(info->references);
+ auto sorted = store->topoSortPaths(info->referencesPossiblyToSelf());
reverse(sorted.begin(), sorted.end());
for (const auto &[n, i] : enumerate(sorted)) {
@@ -328,7 +328,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
for (auto & j : ps) {
if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs);
else if (query == qReferences) {
- for (auto & p : store->queryPathInfo(j)->references)
+ for (auto & p : store->queryPathInfo(j)->referencesPossiblyToSelf())
paths.insert(p);
}
else if (query == qReferrers) {
@@ -857,7 +857,7 @@ static void opServe(Strings opFlags, Strings opArgs)
auto info = store->queryPathInfo(i);
out << store->printStorePath(info->path)
<< (info->deriver ? store->printStorePath(*info->deriver) : "");
- writeStorePaths(*store, out, info->references);
+ writeStorePaths(*store, out, info->referencesPossiblyToSelf());
// !!! Maybe we want compression?
out << info->narSize // downloadSize
<< info->narSize;
@@ -949,7 +949,7 @@ static void opServe(Strings opFlags, Strings opArgs)
if (deriver != "")
info.deriver = store->parseStorePath(deriver);
info.narHash = Hash(readString(in), htSHA256);
- info.references = readStorePaths<StorePathSet>(*store, in);
+ info.setReferencesPossiblyToSelf(readStorePaths<StorePathSet>(*store, in));
in >> info.registrationTime >> info.narSize >> info.ultimate;
info.sigs = readStrings<StringSet>(in);
info.ca = parseContentAddressOpt(readString(in));
diff --git a/src/nix/make-content-addressable.cc b/src/nix/make-content-addressable.cc
index 2fe2e2fb2..d88765949 100644
--- a/src/nix/make-content-addressable.cc
+++ b/src/nix/make-content-addressable.cc
@@ -79,7 +79,7 @@ struct CmdMakeContentAddressable : StorePathsCommand, MixJSON
ValidPathInfo info(store->makeFixedOutputPath(FileIngestionMethod::Recursive, narHash, path.name(), references, hasSelfReference));
info.references = std::move(references);
- if (hasSelfReference) info.references.insert(info.path);
+ info.hasSelfReference = std::move(hasSelfReference);
info.narHash = narHash;
info.narSize = sink.s->size();
info.ca = FixedOutputHash {
diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc
index 7821a5432..fae78c5b4 100644
--- a/src/nix/sigs.cc
+++ b/src/nix/sigs.cc
@@ -65,7 +65,8 @@ struct CmdCopySigs : StorePathsCommand
binary. */
if (info->narHash != info2->narHash ||
info->narSize != info2->narSize ||
- info->references != info2->references)
+ info->references != info2->references ||
+ info->hasSelfReference != info2->hasSelfReference)
continue;
for (auto & sig : info2->sigs)