aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/optimise-store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/optimise-store.cc')
-rw-r--r--src/libstore/optimise-store.cc26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index 89be6ac65..2ca98f46d 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