Fix chroots builds

Chroots are initialised by hard-linking inputs from the Nix store to
the chroot.  This doesn't work if the input has its immutable bit set,
because it's forbidden to create hard links to immutable files.  So
temporarily clear the immutable bit when creating and destroying the
chroot.

Note that making regular files in the Nix store immutable isn't very
reliable, since the bit can easily become cleared: for instance, if we
run the garbage collector after running ‘nix-store --optimise’.  So
maybe we should only make directories immutable.
This commit is contained in:
Eelco Dolstra 2012-02-18 01:23:52 +01:00
parent bd013b6f98
commit 6fe13e6aba
1 changed files with 16 additions and 0 deletions

View File

@ -7,6 +7,7 @@
#include "local-store.hh"
#include "util.hh"
#include "archive.hh"
#include "immutable.hh"
#include <map>
#include <iostream>
@ -771,6 +772,9 @@ private:
/* RAII object to delete the chroot directory. */
boost::shared_ptr<AutoDelete> autoDelChroot;
/* All inputs that are regular files. */
PathSet regularInputPaths;
/* Whether this is a fixed-output derivation. */
bool fixedOutput;
@ -1291,6 +1295,11 @@ void DerivationGoal::buildDone()
/* Delete the chroot (if we were using one). */
autoDelChroot.reset(); /* this runs the destructor */
/* Deleting the chroot will have caused the immutable bits on
hard-linked inputs to be cleared. So set them again. */
foreach (PathSet::iterator, i, regularInputPaths)
makeImmutable(*i);
/* Compute the FS closure of the outputs and register them as
being valid. */
@ -1687,6 +1696,10 @@ void DerivationGoal::startBuilder()
if (S_ISDIR(st.st_mode))
dirsInChroot.insert(*i);
else {
/* Creating a hard link to *i is impossible if its
immutable bit is set. So clear it first. */
makeMutable(*i);
Path p = chrootRootDir + *i;
if (link(i->c_str(), p.c_str()) == -1) {
/* Hard-linking fails if we exceed the maximum
@ -1700,6 +1713,9 @@ void DerivationGoal::startBuilder()
StringSource source(sink.s);
restorePath(p, source);
}
makeImmutable(*i);
regularInputPaths.insert(*i);
}
}