diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2019-10-21 18:48:21 +0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2019-10-21 18:48:21 +0200 |
commit | 9a18f544ac09c3a40e9a87c166edd878a1368c6f (patch) | |
tree | 9a2dcd0d4545f46c2c3e3930239f9a503903db19 /src/libstore/references.cc | |
parent | b82f75464d1e5ae9a00d8004e5dd7b1ca05059e4 (diff) | |
parent | 629b9b0049363e091b76b7f60a8357d9f94733cc (diff) |
Merge remote-tracking branch 'origin/master' into flakes
Diffstat (limited to 'src/libstore/references.cc')
-rw-r--r-- | src/libstore/references.cc | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/src/libstore/references.cc b/src/libstore/references.cc index 0dcc264c3..605ca9815 100644 --- a/src/libstore/references.cc +++ b/src/libstore/references.cc @@ -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}; +} + } |