mirror of
https://github.com/NixOS/nix.git
synced 2025-11-26 04:00:59 +01:00
* Some experimental code for a fully content-addressed Nix store. The
idea is that any component in the Nix store resides has a store path
name that has a hash component equal to the hash of the contents of
that component, i.e.,
hashPartOf(path) = hashOf(contentsAt(path))
E.g., a path /nix/store/nc35k7yr8...-foo would have content hash
nc35k7yr8...
Of course, when building components in the Nix store, we don't know
the content hash until after the component has been built. We
will handle this by building the component at some randomly
generated prefix in the Nix store, and then afterwards *rewriting*
the random prefix to the hash of the actual contents.
The tricky part is components that reference themselves, such as ELF
executables that contain themselves in their RPATH. We can support
this by computing content hashes "modulo" the original prefix, i.e.,
we zero out every occurence of the randomly generated prefix,
compute the content hash, then rewrite the random prefix to the
final location.
This commit is contained in:
parent
4e2877d8fe
commit
049e74ccf6
3 changed files with 191 additions and 1 deletions
|
|
@ -16,3 +16,10 @@ derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def
|
|||
$(perl) ../aterm-helper.pl derivations-ast.hh derivations-ast.cc < derivations-ast.def
|
||||
|
||||
derivations.cc store.cc: derivations-ast.hh
|
||||
|
||||
|
||||
bin_PROGRAMS = testprog
|
||||
|
||||
testprog_SOURCES = store-new.cc
|
||||
testprog_LDADD = ../libutil/libutil.a \
|
||||
../boost/format/libformat.a ${bdb_lib} ${aterm_lib}
|
||||
|
|
|
|||
145
src/libstore/store-new.cc
Normal file
145
src/libstore/store-new.cc
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include "store-new.hh"
|
||||
|
||||
#include "util.hh"
|
||||
#include "archive.hh"
|
||||
|
||||
|
||||
const unsigned int pathHashLen = 32; /* characters */
|
||||
const string nullPathHashRef(pathHashLen, 0);
|
||||
|
||||
|
||||
PathHash::PathHash()
|
||||
{
|
||||
rep = nullPathHashRef;
|
||||
}
|
||||
|
||||
|
||||
PathHash::PathHash(const Hash & h)
|
||||
{
|
||||
assert(h.type == htSHA256);
|
||||
rep = printHash32(compressHash(h, 20));
|
||||
}
|
||||
|
||||
|
||||
string PathHash::toString() const
|
||||
{
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
||||
bool PathHash::isNull() const
|
||||
{
|
||||
return rep == nullPathHashRef;
|
||||
}
|
||||
|
||||
|
||||
bool PathHash::operator ==(const PathHash & hash2) const
|
||||
{
|
||||
debug("foo");
|
||||
return rep == hash2.rep;
|
||||
}
|
||||
|
||||
|
||||
bool PathHash::operator <(const PathHash & hash2) const
|
||||
{
|
||||
debug("bar");
|
||||
return rep < hash2.rep;
|
||||
}
|
||||
|
||||
|
||||
struct CopySink : DumpSink
|
||||
{
|
||||
string s;
|
||||
virtual void operator () (const unsigned char * data, unsigned int len)
|
||||
{
|
||||
s.append((const char *) data, len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CopySource : RestoreSource
|
||||
{
|
||||
string & s;
|
||||
unsigned int pos;
|
||||
CopySource(string & _s) : s(_s), pos(0) { }
|
||||
virtual void operator () (unsigned char * data, unsigned int len)
|
||||
{
|
||||
s.copy((char *) data, len, pos);
|
||||
pos += len;
|
||||
assert(pos <= s.size());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
string rewriteHashes(string s, const HashRewrites & rewrites)
|
||||
{
|
||||
for (HashRewrites::const_iterator i = rewrites.begin();
|
||||
i != rewrites.end(); ++i)
|
||||
{
|
||||
string from = i->first.toString(), to = i->second.toString();
|
||||
|
||||
assert(from.size() == to.size());
|
||||
|
||||
unsigned int j = 0;
|
||||
while ((j = s.find(from, j)) != string::npos) {
|
||||
debug(format("rewriting @ %1%") % j);
|
||||
s.replace(j, to.size(), to);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
PathHash hashModulo(string s, const PathHash & modulus)
|
||||
{
|
||||
if (!modulus.isNull()) {
|
||||
/* Zero out occurences of `modulus'. */
|
||||
HashRewrites rewrites;
|
||||
rewrites[modulus] = PathHash(); /* = null hash */
|
||||
s = rewriteHashes(s, rewrites);
|
||||
}
|
||||
|
||||
return PathHash(hashString(htSHA256, s));
|
||||
}
|
||||
|
||||
|
||||
Path addToStore(const Path & srcPath, const PathHash & selfHash)
|
||||
{
|
||||
debug(format("adding %1%") % srcPath);
|
||||
|
||||
CopySink sink;
|
||||
dumpPath(srcPath, sink);
|
||||
|
||||
PathHash newHash = hashModulo(sink.s, selfHash);
|
||||
|
||||
debug(format("newHash %1%") % newHash.toString());
|
||||
|
||||
if (!selfHash.isNull()) {
|
||||
HashRewrites rewrites;
|
||||
rewrites[selfHash] = newHash;
|
||||
sink.s = rewriteHashes(sink.s, rewrites);
|
||||
PathHash newHash2 = hashModulo(sink.s, newHash);
|
||||
assert(newHash2 == newHash);
|
||||
debug(format("newHash2 %1%") % newHash2.toString());
|
||||
}
|
||||
|
||||
Path path = "./out/" + newHash.toString() + "-" + baseNameOf(srcPath);
|
||||
|
||||
CopySource source(sink.s);
|
||||
restorePath(path, source);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
verbosity = (Verbosity) ((int) 10);
|
||||
|
||||
Path p = addToStore("./bar", PathHash(parseHash32(htSHA256, "8myr6ajc52b5sky7iplgz8jv703ljc0q")));
|
||||
|
||||
cout << p << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
src/libstore/store-new.hh
Normal file
38
src/libstore/store-new.hh
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef __STORE_H
|
||||
#define __STORE_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "hash.hh"
|
||||
#include "db.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct PathHash
|
||||
{
|
||||
private:
|
||||
string rep;
|
||||
public:
|
||||
PathHash();
|
||||
PathHash(const Hash & h);
|
||||
string toString() const;
|
||||
bool PathHash::isNull() const;
|
||||
bool operator ==(const PathHash & hash2) const;
|
||||
bool operator <(const PathHash & hash2) const;
|
||||
};
|
||||
|
||||
|
||||
/* Add the contents of the specified path to the Nix store. Any
|
||||
occurence of the representation of `selfHash' (if not empty) is
|
||||
rewritten to the hash of the new store path. */
|
||||
Path addToStore(const Path & srcPath, const PathHash & selfHash);
|
||||
|
||||
|
||||
/* Rewrite a set of hashes in the given path. */
|
||||
typedef map<PathHash, PathHash> HashRewrites;
|
||||
//Path rewriteHashes(const Path & srcPath, HashRewrites rewrites);
|
||||
|
||||
|
||||
#endif /* !__STORE_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue