diff options
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/local-store.cc | 7 | ||||
-rw-r--r-- | src/libstore/optimise-store.cc | 26 |
2 files changed, 31 insertions, 2 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index a30839643c4b..21b1bdceae2f 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -5,6 +5,7 @@ #include "pathlocks.hh" #include "worker-protocol.hh" #include "derivations.hh" +#include "immutable.hh" #include <iostream> #include <algorithm> @@ -405,6 +406,10 @@ void canonicalisePathMetaData(const Path & path, bool recurse) if (lstat(path.c_str(), &st)) throw SysError(format("getting attributes of path `%1%'") % path); + /* Really make sure that the path is of a supported type. This + has already been checked in dumpPath(). */ + assert(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)); + /* Change ownership to the current uid. If it's a symlink, use lchown if available, otherwise don't bother. Wrong ownership of a symlink doesn't matter, since the owning user can't change @@ -451,6 +456,8 @@ void canonicalisePathMetaData(const Path & path, bool recurse) foreach (Strings::iterator, i, names) canonicalisePathMetaData(path + "/" + *i, true); } + + makeImmutable(path); } diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 89be6ac6529a..2ca98f46ddf4 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -1,5 +1,6 @@ #include "util.hh" #include "local-store.hh" +#include "immutable.hh" #include <sys/types.h> #include <sys/stat.h> @@ -19,6 +20,7 @@ static void makeWritable(const Path & path) struct stat st; if (lstat(path.c_str(), &st)) throw SysError(format("getting attributes of path `%1%'") % path); + if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) makeMutable(path); if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) throw SysError(format("changing writability of `%1%'") % path); } @@ -31,6 +33,8 @@ struct MakeReadOnly ~MakeReadOnly() { try { + /* This will make the path read-only (and restore the + immutable bit on platforms that support it). */ if (path != "") canonicalisePathMetaData(path, false); } catch (...) { ignoreException(); @@ -39,6 +43,14 @@ struct MakeReadOnly }; +struct MakeImmutable +{ + Path path; + MakeImmutable(const Path & path) : path(path) { } + ~MakeImmutable() { makeImmutable(path); } +}; + + static void hashAndLink(bool dryRun, HashToPath & hashToPath, OptimiseStats & stats, const Path & path) { @@ -96,14 +108,24 @@ static void hashAndLink(bool dryRun, HashToPath & hashToPath, /* Make the containing directory writable, but only if it's not the store itself (we don't want or need to - mess with its permissions). */ + mess with its permissions). */ bool mustToggle = !isStorePath(path); if (mustToggle) makeWritable(dirOf(path)); /* When we're done, make the directory read-only again and reset its timestamp back to 0. */ MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : ""); - + + /* If ‘prevPath’ is immutable, we can't create hard links + to it, so make it mutable first (and make it immutable + again when we're done). We also have to make ‘path’ + mutable, otherwise rename() will fail to delete it. */ + makeMutable(prevPath.first); + MakeImmutable mk1(prevPath.first); + + makeMutable(path); + MakeImmutable mk2(path); + if (link(prevPath.first.c_str(), tempLink.c_str()) == -1) { if (errno == EMLINK) { /* Too many links to the same file (>= 32000 on |