Skip to content

Commit

Permalink
Allow hard links between the outputs of a derivation
Browse files Browse the repository at this point in the history
  • Loading branch information
edolstra committed Jun 13, 2013
1 parent cd49ee0 commit 1b6ee8f
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
9 changes: 7 additions & 2 deletions src/libstore/build.cc
Expand Up @@ -844,6 +844,11 @@ class DerivationGoal : public Goal
bool repair;
map<Path, Path> redirectedBadOutputs;

/* Set of inodes seen during calls to canonicalisePathMetaData()
for this build's outputs. This needs to be shared between
outputs to allow hard links between outputs. */
InodesSeen inodesSeen;

/* Magic exit code denoting that setting up the child environment
failed. (It's possible that the child actually returns the
exit code, but ah well.) */
Expand Down Expand Up @@ -1493,7 +1498,7 @@ void DerivationGoal::buildDone()
/* Canonicalise first. This ensures that the path
we're rewriting doesn't contain a hard link to
/etc/shadow or something like that. */
canonicalisePathMetaData(path, buildUser.enabled() ? buildUser.getUID() : -1);
canonicalisePathMetaData(path, buildUser.enabled() ? buildUser.getUID() : -1, inodesSeen);

/* FIXME: this is in-memory. */
StringSink sink;
Expand Down Expand Up @@ -2307,7 +2312,7 @@ void DerivationGoal::computeClosure()
/* Get rid of all weird permissions. This also checks that
all files are owned by the build user, if applicable. */
canonicalisePathMetaData(path,
buildUser.enabled() && rewrittenPaths.find(path) == rewrittenPaths.end() ? buildUser.getUID() : -1);
buildUser.enabled() && rewrittenPaths.find(path) == rewrittenPaths.end() ? buildUser.getUID() : -1, inodesSeen);

/* For this output path, find the references to other paths
contained in it. Compute the SHA-256 NAR hash at the same
Expand Down
15 changes: 8 additions & 7 deletions src/libstore/local-store.cc
Expand Up @@ -500,10 +500,6 @@ void canonicaliseTimestampAndPermissions(const Path & path)
}


typedef std::pair<dev_t, ino_t> Inode;
typedef set<Inode> InodesSeen;


static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSeen & inodesSeen)
{
checkInterrupt();
Expand Down Expand Up @@ -561,10 +557,8 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe
}


void canonicalisePathMetaData(const Path & path, uid_t fromUid)
void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & inodesSeen)
{
InodesSeen inodesSeen;

canonicalisePathMetaData_(path, fromUid, inodesSeen);

/* On platforms that don't have lchown(), the top-level path can't
Expand All @@ -580,6 +574,13 @@ void canonicalisePathMetaData(const Path & path, uid_t fromUid)
}


void canonicalisePathMetaData(const Path & path, uid_t fromUid)
{
InodesSeen inodesSeen;
canonicalisePathMetaData(path, fromUid, inodesSeen);
}


void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation & drv)
{
string drvName = storePathToName(drvPath);
Expand Down
5 changes: 5 additions & 0 deletions src/libstore/local-store.hh
Expand Up @@ -305,6 +305,10 @@ private:
};


typedef std::pair<dev_t, ino_t> Inode;
typedef set<Inode> InodesSeen;


/* "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 1 (i.e.,
Expand All @@ -313,6 +317,7 @@ private:
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, uid_t fromUid, InodesSeen & inodesSeen);
void canonicalisePathMetaData(const Path & path, uid_t fromUid);

void canonicaliseTimestampAndPermissions(const Path & path);
Expand Down

0 comments on commit 1b6ee8f

Please sign in to comment.