* Renamed normalise.cc' -> build.cc', `storeexprs.cc' ->

`derivations.cc', etc.
* Store the SHA-256 content hash of store paths in the database after
  they have been built/added.  This is so that we can check whether
  the store has been messed with (a la `rpm --verify').
* When registering path validity, verify that the closure property
  holds.
This commit is contained in:
Eelco Dolstra 2005-01-19 16:39:47 +00:00
parent ef5f254a55
commit 96de272b48
19 changed files with 128 additions and 98 deletions

View file

@ -1,5 +1,5 @@
#include "nixexpr.hh" #include "nixexpr.hh"
#include "storeexpr.hh" #include "derivations.hh"
#include "nixexpr-ast.hh" #include "nixexpr-ast.hh"

View file

@ -1,4 +1,4 @@
#include "normalise.hh" #include "build.hh"
#include "eval.hh" #include "eval.hh"
#include "globals.hh" #include "globals.hh"
#include "nixexpr-ast.hh" #include "nixexpr-ast.hh"

View file

@ -55,7 +55,7 @@ void checkStoreNotSymlink(Path path)
} }
void initStoreExprHelpers(); void initDerivationsHelpers();
/* Initialize and reorder arguments, then call the actual argument /* Initialize and reorder arguments, then call the actual argument
@ -105,7 +105,7 @@ static void initAndRun(int argc, char * * argv)
if (lt != "") setLogType(lt); if (lt != "") setLogType(lt);
/* ATerm stuff. !!! find a better place to put this */ /* ATerm stuff. !!! find a better place to put this */
initStoreExprHelpers(); initDerivationsHelpers();
/* Put the arguments in a vector. */ /* Put the arguments in a vector. */
Strings args, remaining; Strings args, remaining;

View file

@ -1,18 +1,18 @@
noinst_LIBRARIES = libstore.a noinst_LIBRARIES = libstore.a
libstore_a_SOURCES = \ libstore_a_SOURCES = \
store.cc store.hh storeexpr.cc storeexpr.hh \ store.cc store.hh derivations.cc derivations.hh \
normalise.cc misc.cc normalise.hh \ build.cc misc.cc build.hh \
globals.cc globals.hh db.cc db.hh \ globals.cc globals.hh db.cc db.hh \
references.cc references.hh pathlocks.cc pathlocks.hh \ references.cc references.hh pathlocks.cc pathlocks.hh \
gc.cc gc.hh storeexpr-ast.hh gc.cc gc.hh derivations-ast.hh
EXTRA_DIST = storeexpr-ast.def storeexpr-ast.cc EXTRA_DIST = derivations-ast.def derivations-ast.cc
AM_CXXFLAGS = -Wall \ AM_CXXFLAGS = -Wall \
-I.. ${bdb_include} ${aterm_include} -I../libutil -I.. ${bdb_include} ${aterm_include} -I../libutil
storeexpr-ast.cc storeexpr-ast.hh: ../aterm-helper.pl storeexpr-ast.def derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def
$(perl) ../aterm-helper.pl storeexpr-ast.hh storeexpr-ast.cc < storeexpr-ast.def $(perl) ../aterm-helper.pl derivations-ast.hh derivations-ast.cc < derivations-ast.def
storeexpr.cc: storeexpr-ast.hh derivations.cc: derivations-ast.hh

View file

@ -5,13 +5,11 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <utime.h>
#include "normalise.hh" #include "build.hh"
#include "references.hh" #include "references.hh"
#include "pathlocks.hh" #include "pathlocks.hh"
#include "globals.hh" #include "globals.hh"
@ -285,60 +283,6 @@ const char * * strings2CharPtrs(const Strings & ss)
} }
/* "Fix", or canonicalise, the meta-data of the files in a store path
after it has been built. In particular:
- the last modification date on each file is set to 0 (i.e.,
00:00:00 1/1/1970 UTC)
- the permissions are set of 444 or 555 (i.e., read-only with or
without execute permission; setuid bits etc. are cleared)
- the owner and group are set to the Nix user and group, if we're
in a setuid Nix installation
*/
void canonicalisePathMetaData(const Path & path)
{
checkInterrupt();
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path `%1%'") % path);
if (!S_ISLNK(st.st_mode)) {
/* Mask out all type related bits. */
mode_t mode = st.st_mode & ~S_IFMT;
if (mode != 0444 && mode != 0555) {
mode = (st.st_mode & S_IFMT)
| 0444
| (st.st_mode & S_IXUSR ? 0111 : 0);
if (chmod(path.c_str(), mode) == -1)
throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
}
if (st.st_uid != getuid() || st.st_gid != getgid()) {
if (chown(path.c_str(), getuid(), getgid()) == -1)
throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
% path % getuid() % getgid());
}
if (st.st_mtime != 0) {
struct utimbuf utimbuf;
utimbuf.actime = st.st_atime;
utimbuf.modtime = 0;
if (utime(path.c_str(), &utimbuf) == -1)
throw SysError(format("changing modification time of `%1%'") % path);
}
}
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
canonicalisePathMetaData(path + "/" + *i);
}
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -1041,6 +985,7 @@ void DerivationGoal::computeClosure()
format("determining closure for `%1%'") % drvPath); format("determining closure for `%1%'") % drvPath);
map<Path, PathSet> allReferences; map<Path, PathSet> allReferences;
map<Path, Hash> contentHashes;
/* Check whether the output paths were created, and grep each /* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all output path to determine what other paths it references. Also make all
@ -1109,6 +1054,12 @@ void DerivationGoal::computeClosure()
} }
allReferences[path] = references; allReferences[path] = references;
/* Hash the contents of the path. The hash is stored in the
database so that we can verify later on whether nobody has
messed with the store. !!! inefficient: it would be nice
if we could combine this with filterReferences(). */
contentHashes[path] = hashPath(htSHA256, path);
} }
/* Register each output path as valid, and register the sets of /* Register each output path as valid, and register the sets of
@ -1127,7 +1078,8 @@ void DerivationGoal::computeClosure()
for (DerivationOutputs::iterator i = drv.outputs.begin(); for (DerivationOutputs::iterator i = drv.outputs.begin();
i != drv.outputs.end(); ++i) i != drv.outputs.end(); ++i)
{ {
registerValidPath(txn, i->second.path); registerValidPath(txn, i->second.path,
contentHashes[i->second.path]);
setReferences(txn, i->second.path, setReferences(txn, i->second.path,
allReferences[i->second.path]); allReferences[i->second.path]);
} }
@ -1460,9 +1412,11 @@ void SubstitutionGoal::finished()
canonicalisePathMetaData(storePath); canonicalisePathMetaData(storePath);
Hash contentHash = hashPath(htSHA256, storePath);
Transaction txn; Transaction txn;
createStoreTransaction(txn); createStoreTransaction(txn);
registerValidPath(txn, storePath); registerValidPath(txn, storePath, contentHash);
txn.commit(); txn.commit();
outputLock->setDeletion(true); outputLock->setDeletion(true);

View file

@ -1,7 +1,7 @@
#ifndef __NORMALISE_H #ifndef __BUILD_H
#define __NORMALISE_H #define __BUILD_H
#include "storeexpr.hh" #include "derivations.hh"
/* Perform the specified derivations, if necessary. That is, do /* Perform the specified derivations, if necessary. That is, do
whatever is necessary to create the output paths of the derivation. whatever is necessary to create the output paths of the derivation.
@ -44,4 +44,4 @@ void computeFSClosure(const Path & storePath,
void storePathRequisites(const Path & storePath, void storePathRequisites(const Path & storePath,
bool includeOutputs, PathSet & paths); bool includeOutputs, PathSet & paths);
#endif /* !__NORMALISE_H */ #endif /* !__BUILD_H */

View file

@ -1,4 +1,4 @@
init initStoreExprHelpers init initDerivationsHelpers
Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm | Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm |

View file

@ -1,9 +1,9 @@
#include "storeexpr.hh" #include "derivations.hh"
#include "globals.hh" #include "globals.hh"
#include "store.hh" #include "store.hh"
#include "storeexpr-ast.hh" #include "derivations-ast.hh"
#include "storeexpr-ast.cc" #include "derivations-ast.cc"
Hash hashTerm(ATerm t) Hash hashTerm(ATerm t)

View file

@ -1,5 +1,5 @@
#ifndef __STOREEXPR_H #ifndef __DERIVATIONS_H
#define __STOREEXPR_H #define __DERIVATIONS_H
#include "aterm.hh" #include "aterm.hh"
#include "store.hh" #include "store.hh"
@ -59,4 +59,4 @@ ATerm unparseDerivation(const Derivation & drv);
bool isDerivation(const string & fileName); bool isDerivation(const string & fileName);
#endif /* !__STOREEXPR_H */ #endif /* !__DERIVATIONS_H */

View file

@ -1,5 +1,5 @@
#include "normalise.hh"
#include "globals.hh" #include "globals.hh"
#include "gc.hh"
#include <sys/types.h> #include <sys/types.h>

View file

@ -1,7 +1,7 @@
#ifndef __GC_H #ifndef __GC_H
#define __GC_H #define __GC_H
#include "storeexpr.hh" #include "util.hh"
/* Determine the set of "live" store paths, given a set of root store /* Determine the set of "live" store paths, given a set of root store

View file

@ -1,4 +1,4 @@
#include "normalise.hh" #include "build.hh"
Derivation derivationFromPath(const Path & drvPath) Derivation derivationFromPath(const Path & drvPath)

View file

@ -2,7 +2,10 @@
#include <algorithm> #include <algorithm>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <utime.h>
#include "store.hh" #include "store.hh"
#include "globals.hh" #include "globals.hh"
@ -181,6 +184,51 @@ void assertStorePath(const Path & path)
} }
void canonicalisePathMetaData(const Path & path)
{
checkInterrupt();
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path `%1%'") % path);
if (!S_ISLNK(st.st_mode)) {
/* Mask out all type related bits. */
mode_t mode = st.st_mode & ~S_IFMT;
if (mode != 0444 && mode != 0555) {
mode = (st.st_mode & S_IFMT)
| 0444
| (st.st_mode & S_IXUSR ? 0111 : 0);
if (chmod(path.c_str(), mode) == -1)
throw SysError(format("changing mode of `%1%' to %2$o") % path % mode);
}
if (st.st_uid != getuid() || st.st_gid != getgid()) {
if (chown(path.c_str(), getuid(), getgid()) == -1)
throw SysError(format("changing owner/group of `%1%' to %2%/%3%")
% path % getuid() % getgid());
}
if (st.st_mtime != 0) {
struct utimbuf utimbuf;
utimbuf.actime = st.st_atime;
utimbuf.modtime = 0;
if (utime(path.c_str(), &utimbuf) == -1)
throw SysError(format("changing modification time of `%1%'") % path);
}
}
if (S_ISDIR(st.st_mode)) {
Strings names = readDirectory(path);
for (Strings::iterator i = names.begin(); i != names.end(); ++i)
canonicalisePathMetaData(path + "/" + *i);
}
}
static bool isValidPathTxn(const Path & path, const Transaction & txn) static bool isValidPathTxn(const Path & path, const Transaction & txn)
{ {
string s; string s;
@ -318,12 +366,24 @@ void clearSubstitutes()
} }
void registerValidPath(const Transaction & txn, const Path & _path) void registerValidPath(const Transaction & txn,
const Path & _path, const Hash & hash)
{ {
Path path(canonPath(_path)); Path path(canonPath(_path));
assertStorePath(path); assertStorePath(path);
assert(hash.type == htSHA256);
debug(format("registering path `%1%'") % path); debug(format("registering path `%1%'") % path);
nixDB.setString(txn, dbValidPaths, path, ""); nixDB.setString(txn, dbValidPaths, path, "sha256:" + printHash(hash));
/* Check that all referenced paths are also valid. */
Paths references;
nixDB.queryStrings(txn, dbReferences, path, references);
for (Paths::iterator i = references.begin(); i != references.end(); ++i)
if (!isValidPathTxn(*i, txn))
throw Error(format("cannot register path `%1%' as valid, since its reference `%2%' is invalid")
% path % *i);
} }
@ -385,10 +445,10 @@ Path addToStore(const Path & _srcPath)
throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)") throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)")
% srcPath % dstPath % printHash(h) % printHash(h2)); % srcPath % dstPath % printHash(h) % printHash(h2));
makePathReadOnly(dstPath); canonicalisePathMetaData(dstPath);
Transaction txn(nixDB); Transaction txn(nixDB);
registerValidPath(txn, dstPath); registerValidPath(txn, dstPath, h);
txn.commit(); txn.commit();
} }
@ -417,10 +477,10 @@ Path addTextToStore(const string & suffix, const string & s)
writeStringToFile(dstPath, s); writeStringToFile(dstPath, s);
makePathReadOnly(dstPath); canonicalisePathMetaData(dstPath);
Transaction txn(nixDB); Transaction txn(nixDB);
registerValidPath(txn, dstPath); registerValidPath(txn, dstPath, hashPath(htSHA256, dstPath));
txn.commit(); txn.commit();
} }

View file

@ -51,12 +51,28 @@ Substitutes querySubstitutes(const Path & srcPath);
/* Deregister all substitutes. */ /* Deregister all substitutes. */
void clearSubstitutes(); void clearSubstitutes();
/* Register the validity of a path. */ /* Register the validity of a path, i.e., that `path' exists, that the
void registerValidPath(const Transaction & txn, const Path & path); paths referenced by it exists, and in the case of an output path of
a derivation, that it has been produced by a succesful execution of
the derivation (or something equivalent). Also register the hash
of the file system contents of the path. The hash must be a
SHA-256 hash. */
void registerValidPath(const Transaction & txn,
const Path & path, const Hash & hash);
/* Throw an exception if `path' is not directly in the Nix store. */ /* Throw an exception if `path' is not directly in the Nix store. */
void assertStorePath(const Path & path); void assertStorePath(const Path & path);
/* "Fix", or canonicalise, the meta-data of the files in a store path
after it has been built. In particular:
- the last modification date on each file is set to 0 (i.e.,
00:00:00 1/1/1970 UTC)
- the permissions are set of 444 or 555 (i.e., read-only with or
without execute permission; setuid bits etc. are cleared)
- the owner and group are set to the Nix user and group, if we're
in a setuid Nix installation. */
void canonicalisePathMetaData(const Path & path);
/* Checks whether a path is valid. */ /* Checks whether a path is valid. */
bool isValidPath(const Path & path); bool isValidPath(const Path & path);

View file

@ -1,7 +1,7 @@
#include "profiles.hh" #include "profiles.hh"
#include "names.hh" #include "names.hh"
#include "globals.hh" #include "globals.hh"
#include "normalise.hh" #include "build.hh"
#include "shared.hh" #include "shared.hh"
#include "parser.hh" #include "parser.hh"
#include "eval.hh" #include "eval.hh"

View file

@ -2,7 +2,7 @@
#include <iostream> #include <iostream>
#include "globals.hh" #include "globals.hh"
#include "normalise.hh" #include "build.hh"
#include "shared.hh" #include "shared.hh"
#include "eval.hh" #include "eval.hh"
#include "parser.hh" #include "parser.hh"

View file

@ -1,5 +1,5 @@
#include "dotgraph.hh" #include "dotgraph.hh"
#include "normalise.hh" #include "build.hh"
#if 0 #if 0

View file

@ -1,7 +1,7 @@
#ifndef __DOTGRAPH_H #ifndef __DOTGRAPH_H
#define __DOTGRAPH_H #define __DOTGRAPH_H
#include "storeexpr.hh" #include "util.hh"
void printDotGraph(const PathSet & roots); void printDotGraph(const PathSet & roots);

View file

@ -1,7 +1,7 @@
#include <iostream> #include <iostream>
#include "globals.hh" #include "globals.hh"
#include "normalise.hh" #include "build.hh"
#include "gc.hh" #include "gc.hh"
#include "archive.hh" #include "archive.hh"
#include "shared.hh" #include "shared.hh"
@ -187,7 +187,7 @@ static void opValidPath(Strings opFlags, Strings opArgs)
createStoreTransaction(txn); createStoreTransaction(txn);
for (Strings::iterator i = opArgs.begin(); for (Strings::iterator i = opArgs.begin();
i != opArgs.end(); ++i) i != opArgs.end(); ++i)
registerValidPath(txn, *i); registerValidPath(txn, *i, hashPath(htSHA256, *i));
txn.commit(); txn.commit();
} }