mirror of
https://github.com/NixOS/nix.git
synced 2025-11-21 01:39:36 +01:00
Merge remote-tracking branch 'origin/master' into flakes
This commit is contained in:
commit
9a18f544ac
16 changed files with 307 additions and 65 deletions
|
|
@ -728,23 +728,6 @@ HookInstance::~HookInstance()
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
typedef map<std::string, std::string> StringRewrites;
|
||||
|
||||
|
||||
std::string rewriteStrings(std::string s, const StringRewrites & rewrites)
|
||||
{
|
||||
for (auto & i : rewrites) {
|
||||
size_t j = 0;
|
||||
while ((j = s.find(i.first, j)) != string::npos)
|
||||
s.replace(j, i.first.size(), i.second);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;
|
||||
|
||||
class SubstitutionGoal;
|
||||
|
|
@ -866,7 +849,7 @@ private:
|
|||
#endif
|
||||
|
||||
/* Hash rewriting. */
|
||||
StringRewrites inputRewrites, outputRewrites;
|
||||
StringMap inputRewrites, outputRewrites;
|
||||
typedef map<Path, Path> RedirectedOutputs;
|
||||
RedirectedOutputs redirectedOutputs;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "worker-protocol.hh"
|
||||
#include "derivations.hh"
|
||||
#include "nar-info.hh"
|
||||
#include "references.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
|
@ -1002,17 +1003,24 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
|||
|
||||
/* While restoring the path from the NAR, compute the hash
|
||||
of the NAR. */
|
||||
HashSink hashSink(htSHA256);
|
||||
std::unique_ptr<AbstractHashSink> hashSink;
|
||||
if (info.ca == "")
|
||||
hashSink = std::make_unique<HashSink>(htSHA256);
|
||||
else {
|
||||
if (!info.references.empty())
|
||||
settings.requireExperimentalFeature("ca-references");
|
||||
hashSink = std::make_unique<HashModuloSink>(htSHA256, storePathToHash(info.path));
|
||||
}
|
||||
|
||||
LambdaSource wrapperSource([&](unsigned char * data, size_t len) -> size_t {
|
||||
size_t n = source.read(data, len);
|
||||
hashSink(data, n);
|
||||
(*hashSink)(data, n);
|
||||
return n;
|
||||
});
|
||||
|
||||
restorePath(realPath, wrapperSource);
|
||||
|
||||
auto hashResult = hashSink.finish();
|
||||
auto hashResult = hashSink->finish();
|
||||
|
||||
if (hashResult.first != info.narHash)
|
||||
throw Error("hash mismatch importing path '%s';\n wanted: %s\n got: %s",
|
||||
|
|
@ -1234,7 +1242,15 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
|
|||
|
||||
/* Check the content hash (optionally - slow). */
|
||||
printMsg(lvlTalkative, format("checking contents of '%1%'") % i);
|
||||
HashResult current = hashPath(info->narHash.type, toRealPath(i));
|
||||
|
||||
std::unique_ptr<AbstractHashSink> hashSink;
|
||||
if (info->ca == "")
|
||||
hashSink = std::make_unique<HashSink>(info->narHash.type);
|
||||
else
|
||||
hashSink = std::make_unique<HashModuloSink>(info->narHash.type, storePathToHash(info->path));
|
||||
|
||||
dumpPath(toRealPath(i), *hashSink);
|
||||
auto current = hashSink->finish();
|
||||
|
||||
if (info->narHash != nullHash && info->narHash != current.first) {
|
||||
printError(format("path '%1%' was modified! "
|
||||
|
|
|
|||
|
|
@ -118,4 +118,66 @@ PathSet scanForReferences(const string & path,
|
|||
}
|
||||
|
||||
|
||||
RewritingSink::RewritingSink(const std::string & from, const std::string & to, Sink & nextSink)
|
||||
: from(from), to(to), nextSink(nextSink)
|
||||
{
|
||||
assert(from.size() == to.size());
|
||||
}
|
||||
|
||||
void RewritingSink::operator () (const unsigned char * data, size_t len)
|
||||
{
|
||||
std::string s(prev);
|
||||
s.append((const char *) data, len);
|
||||
|
||||
size_t j = 0;
|
||||
while ((j = s.find(from, j)) != string::npos) {
|
||||
matches.push_back(pos + j);
|
||||
s.replace(j, from.size(), to);
|
||||
}
|
||||
|
||||
prev = s.size() < from.size() ? s : std::string(s, s.size() - from.size() + 1, from.size() - 1);
|
||||
|
||||
auto consumed = s.size() - prev.size();
|
||||
|
||||
pos += consumed;
|
||||
|
||||
if (consumed) nextSink((unsigned char *) s.data(), consumed);
|
||||
}
|
||||
|
||||
void RewritingSink::flush()
|
||||
{
|
||||
if (prev.empty()) return;
|
||||
pos += prev.size();
|
||||
nextSink((unsigned char *) prev.data(), prev.size());
|
||||
prev.clear();
|
||||
}
|
||||
|
||||
HashModuloSink::HashModuloSink(HashType ht, const std::string & modulus)
|
||||
: hashSink(ht)
|
||||
, rewritingSink(modulus, std::string(modulus.size(), 0), hashSink)
|
||||
{
|
||||
}
|
||||
|
||||
void HashModuloSink::operator () (const unsigned char * data, size_t len)
|
||||
{
|
||||
rewritingSink(data, len);
|
||||
}
|
||||
|
||||
HashResult HashModuloSink::finish()
|
||||
{
|
||||
rewritingSink.flush();
|
||||
|
||||
/* Hash the positions of the self-references. This ensures that a
|
||||
NAR with self-references and a NAR with some of the
|
||||
self-references already zeroed out do not produce a hash
|
||||
collision. FIXME: proof. */
|
||||
for (auto & pos : rewritingSink.matches) {
|
||||
auto s = fmt("|%d", pos);
|
||||
hashSink((unsigned char *) s.data(), s.size());
|
||||
}
|
||||
|
||||
auto h = hashSink.finish();
|
||||
return {h.first, rewritingSink.pos};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,32 @@ namespace nix {
|
|||
|
||||
PathSet scanForReferences(const Path & path, const PathSet & refs,
|
||||
HashResult & hash);
|
||||
|
||||
|
||||
struct RewritingSink : Sink
|
||||
{
|
||||
std::string from, to, prev;
|
||||
Sink & nextSink;
|
||||
uint64_t pos = 0;
|
||||
|
||||
std::vector<uint64_t> matches;
|
||||
|
||||
RewritingSink(const std::string & from, const std::string & to, Sink & nextSink);
|
||||
|
||||
void operator () (const unsigned char * data, size_t len) override;
|
||||
|
||||
void flush();
|
||||
};
|
||||
|
||||
struct HashModuloSink : AbstractHashSink
|
||||
{
|
||||
HashSink hashSink;
|
||||
RewritingSink rewritingSink;
|
||||
|
||||
HashModuloSink(HashType ht, const std::string & modulus);
|
||||
|
||||
void operator () (const unsigned char * data, size_t len) override;
|
||||
|
||||
HashResult finish() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,15 +205,27 @@ Path Store::makeOutputPath(const string & id,
|
|||
}
|
||||
|
||||
|
||||
Path Store::makeFixedOutputPath(bool recursive,
|
||||
const Hash & hash, const string & name) const
|
||||
static std::string makeType(string && type, const PathSet & references)
|
||||
{
|
||||
return hash.type == htSHA256 && recursive
|
||||
? makeStorePath("source", hash, name)
|
||||
: makeStorePath("output:out", hashString(htSHA256,
|
||||
for (auto & i : references) {
|
||||
type += ":";
|
||||
type += i;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
Path Store::makeFixedOutputPath(bool recursive,
|
||||
const Hash & hash, const string & name, const PathSet & references) const
|
||||
{
|
||||
if (hash.type == htSHA256 && recursive) {
|
||||
return makeStorePath(makeType("source", references), hash, name);
|
||||
} else {
|
||||
assert(references.empty());
|
||||
return makeStorePath("output:out", hashString(htSHA256,
|
||||
"fixed:out:" + (recursive ? (string) "r:" : "") +
|
||||
hash.to_string(Base16) + ":"),
|
||||
name);
|
||||
hash.to_string(Base16) + ":"), name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -224,12 +236,7 @@ Path Store::makeTextPath(const string & name, const Hash & hash,
|
|||
/* Stuff the references (if any) into the type. This is a bit
|
||||
hacky, but we can't put them in `s' since that would be
|
||||
ambiguous. */
|
||||
string type = "text";
|
||||
for (auto & i : references) {
|
||||
type += ":";
|
||||
type += i;
|
||||
}
|
||||
return makeStorePath(type, hash, name);
|
||||
return makeStorePath(makeType("text", references), hash, name);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -780,8 +787,9 @@ bool ValidPathInfo::isContentAddressed(const Store & store) const
|
|||
else if (hasPrefix(ca, "fixed:")) {
|
||||
bool recursive = ca.compare(6, 2, "r:") == 0;
|
||||
Hash hash(std::string(ca, recursive ? 8 : 6));
|
||||
if (references.empty() &&
|
||||
store.makeFixedOutputPath(recursive, hash, storePathToName(path)) == path)
|
||||
auto refs = references;
|
||||
replaceInSet(refs, path, std::string("self"));
|
||||
if (store.makeFixedOutputPath(recursive, hash, storePathToName(path), refs) == path)
|
||||
return true;
|
||||
else
|
||||
warn();
|
||||
|
|
|
|||
|
|
@ -304,7 +304,8 @@ public:
|
|||
const Hash & hash, const string & name) const;
|
||||
|
||||
Path makeFixedOutputPath(bool recursive,
|
||||
const Hash & hash, const string & name) const;
|
||||
const Hash & hash, const string & name,
|
||||
const PathSet & references = {}) const;
|
||||
|
||||
Path makeTextPath(const string & name, const Hash & hash,
|
||||
const PathSet & references) const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue