From 9530cc31700f68fd229eee69eabd2baa099f404a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 14 Jan 2005 13:51:38 +0000 Subject: [PATCH] * Start move towards SHA-256 hashes instead of MD5. * Start cleaning up unique store path generation (they weren't always unique; in particular the suffix ("-aterm-2.2", "-builder.sh") was not part of the hash, therefore changes to the suffix would cause multiple store objects with the same hash). --- src/libexpr/primops.cc | 19 +++++++++++++++---- src/libmain/shared.cc | 8 ++++---- src/libstore/normalise.cc | 2 +- src/libstore/store.cc | 36 ++++++++++++++++++++++++++++++------ src/libstore/store.hh | 11 +++++++---- src/libstore/storeexpr.cc | 16 +++------------- src/libutil/hash.cc | 1 + src/libutil/hash.hh | 2 +- src/nix-env/main.cc | 2 +- 9 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index f73e60e38..59b85a6d6 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -59,7 +59,7 @@ static Path copyAtom(EvalState & state, const Path & srcPath) ne.closure.elems[dstPath] = elem; Hash drvHash = hashDerivation(state, ne); - Path drvPath = writeTerm(unparseStoreExpr(ne), ""); + Path drvPath = writeTerm(unparseStoreExpr(ne), "c"); state.drvHashes.insert(make_pair(drvPath, drvHash)); state.drvRoots[drvPath] = ne.closure.roots; @@ -250,21 +250,32 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args) throw Error(format("invalid character `%1%' in derivation name `%2%'") % *i % drvName); } + + /* Construct the "masked" derivation store expression, which is + the final one except that the list of output paths is set to + the set of output names, and the corresponding environment + variables have an empty value. This ensures that changes in + the set of output names do get reflected in the hash. */ + ne.derivation.env["out"] = ""; + ne.derivation.outputs.insert("out"); /* Determine the output path by hashing the Nix expression with no outputs to produce a unique but deterministic path name for this derivation. */ if (!outHashGiven) outHash = hashDerivation(state, ne); - Path outPath = canonPath(nixStore + "/" + - ((string) outHash).c_str() + "-" + drvName); + Path outPath = makeStorePath("output:out", + outHash, drvName); + + /* Construct the final derivation store expression. */ ne.derivation.env["out"] = outPath; + ne.derivation.outputs.clear(); ne.derivation.outputs.insert(outPath); /* Write the resulting term into the Nix store directory. */ Hash drvHash = outHashGiven ? hashString((string) outHash + outPath, htMD5) : hashDerivation(state, ne); - Path drvPath = writeTerm(unparseStoreExpr(ne), "-d-" + drvName); + Path drvPath = writeTerm(unparseStoreExpr(ne), "d-" + drvName); printMsg(lvlChatty, format("instantiated `%1%' -> `%2%'") % drvName % drvPath); diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index f608afd84..40750779c 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -69,10 +69,10 @@ static void initAndRun(int argc, char * * argv) } /* Setup Nix paths. */ - nixStore = getEnv("NIX_STORE_DIR", canonPath(NIX_STORE_DIR)); - nixDataDir = getEnv("NIX_DATA_DIR", canonPath(NIX_DATA_DIR)); - nixLogDir = getEnv("NIX_LOG_DIR", canonPath(NIX_LOG_DIR)); - nixStateDir = getEnv("NIX_STATE_DIR", canonPath(NIX_STATE_DIR)); + nixStore = canonPath(getEnv("NIX_STORE_DIR", NIX_STORE_DIR)); + nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR)); + nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)); + nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR)); nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db"); /* Check that the store directory and its parent are not diff --git a/src/libstore/normalise.cc b/src/libstore/normalise.cc index d535fe2ee..7907325a9 100644 --- a/src/libstore/normalise.cc +++ b/src/libstore/normalise.cc @@ -1137,7 +1137,7 @@ void NormalisationGoal::createClosure() /* Write the normal form. This does not have to occur in the transaction below because writing terms is idem-potent. */ ATerm nfTerm = unparseStoreExpr(nf); - Path nfPath = writeTerm(nfTerm, "-s"); + Path nfPath = writeTerm(nfTerm, "s"); /* Register each output path, and register the normal form. This is wrapped in one database transaction to ensure that if we diff --git a/src/libstore/store.cc b/src/libstore/store.cc index b3b0dfc4f..3a76618a5 100644 --- a/src/libstore/store.cc +++ b/src/libstore/store.cc @@ -411,19 +411,34 @@ static void invalidatePath(const Path & path, Transaction & txn) } +Path makeStorePath(const string & type, + Hash & hash, const string & suffix) +{ + /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ + string s = type + ":sha256:" + (string) hash + ":" + + nixStore + ":" + suffix; + + Hash nameHash = hashString(s, htSHA256); + + printMsg(lvlError, format("name input: %1% -> %2%") % s % (string) nameHash); + + return nixStore + "/" + (string) nameHash + "-" + suffix; +} + + Path addToStore(const Path & _srcPath) { Path srcPath(absPath(_srcPath)); debug(format("adding `%1%' to the store") % srcPath); - Hash h(htMD5); + Hash h(htSHA256); { SwitchToOriginalUser sw; - h = hashPath(srcPath, htMD5); + h = hashPath(srcPath, htSHA256); } string baseName = baseNameOf(srcPath); - Path dstPath = canonPath(nixStore + "/" + (string) h + "-" + baseName); + Path dstPath = makeStorePath("source", h, baseName); if (!readOnlyMode && !isValidPath(dstPath)) { @@ -443,6 +458,11 @@ Path addToStore(const Path & _srcPath) copyPath(srcPath, dstPath); + Hash h2 = hashPath(dstPath, htSHA256); + if (h != h2) + throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)") + % srcPath % dstPath % (string) h % (string) h2); + makePathReadOnly(dstPath); Transaction txn(nixDB); @@ -457,11 +477,13 @@ Path addToStore(const Path & _srcPath) } -void addTextToStore(const Path & dstPath, const string & s) +Path addTextToStore(const string & suffix, const string & s) { - assertStorePath(dstPath); + Hash hash = hashString(s, htSHA256); + + Path dstPath = makeStorePath("text", hash, suffix); - if (!isValidPath(dstPath)) { + if (!readOnlyMode && !isValidPath(dstPath)) { PathSet lockPaths; lockPaths.insert(dstPath); @@ -482,6 +504,8 @@ void addTextToStore(const Path & dstPath, const string & s) outputLock.setDeletion(true); } + + return dstPath; } diff --git a/src/libstore/store.hh b/src/libstore/store.hh index 6a989874b..25a6bc8b9 100644 --- a/src/libstore/store.hh +++ b/src/libstore/store.hh @@ -81,14 +81,17 @@ void assertStorePath(const Path & path); /* Checks whether a path is valid. */ bool isValidPath(const Path & path); +/* Constructs a unique store path name. */ +Path makeStorePath(const string & type, + Hash & hash, const string & suffix); + /* Copy the contents of a path to the store and register the validity the resulting path. The resulting path is returned. */ Path addToStore(const Path & srcPath); -/* Like addToStore, but the path of the output is given, and the - contents written to the output path is a regular file containing - the given string. */ -void addTextToStore(const Path & dstPath, const string & s); +/* Like addToStore, but the contents written to the output path is a + regular file containing the given string. */ +Path addTextToStore(const string & suffix, const string & s); /* Delete a value from the nixStore directory. */ void deleteFromStore(const Path & path); diff --git a/src/libstore/storeexpr.cc b/src/libstore/storeexpr.cc index 3308d5b06..de29959ed 100644 --- a/src/libstore/storeexpr.cc +++ b/src/libstore/storeexpr.cc @@ -14,19 +14,9 @@ Hash hashTerm(ATerm t) Path writeTerm(ATerm t, const string & suffix) { - /* The id of a term is its hash. */ - Hash h = hashTerm(t); - - Path path = canonPath(nixStore + "/" + - (string) h + suffix + ".store"); - - if (!readOnlyMode && !isValidPath(path)) { - char * s = ATwriteToString(t); - if (!s) throw Error(format("cannot write aterm to `%1%'") % path); - addTextToStore(path, string(s)); - } - - return path; + char * s = ATwriteToString(t); + if (!s) throw Error("cannot print aterm"); + return addTextToStore(suffix + ".store", string(s)); } diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index 599d375dc..cd7043090 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -22,6 +22,7 @@ Hash::Hash(HashType type) else if (type == htSHA1) hashSize = sha1HashSize; else if (type == htSHA256) hashSize = sha256HashSize; else throw Error("unknown hash type"); + assert(hashSize <= maxHashSize); memset(hash, 0, hashSize); } diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh index d82cd87a2..4490d2ff7 100644 --- a/src/libutil/hash.hh +++ b/src/libutil/hash.hh @@ -18,7 +18,7 @@ const int sha256HashSize = 32; struct Hash { - static const unsigned int maxHashSize = 20; + static const unsigned int maxHashSize = 32; unsigned int hashSize; unsigned char hash[maxHashSize]; diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc index 5321b294a..fc65dcfc3 100644 --- a/src/nix-env/main.cc +++ b/src/nix-env/main.cc @@ -216,7 +216,7 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs, /* Also write a copy of the list of inputs to the store; we need it for future modifications of the environment. */ - Path inputsFile = writeTerm(inputs2, "-env-inputs"); + Path inputsFile = writeTerm(inputs2, "env-inputs"); Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3( makeBind(toATerm("system"),