summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-01-03 12:59:23 +0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-01-03 12:59:23 +0100
commitdef5160b614a59a0aa96fe2252e3daa00146e061 (patch)
tree3ec0b2ade78dfbf00399246fea86d3706ce0db93
parent0a4e90395c3286a246b816575351b9f2016976ba (diff)
downloadguix-def5160b614a59a0aa96fe2252e3daa00146e061.tar.gz
Clear any immutable bits in the Nix store
Doing this once makes subsequent operations like garbage collecting
more efficient since we don't have to call makeMutable() first.
-rw-r--r--doc/manual/release-notes.xml13
-rw-r--r--src/libstore/build.cc9
-rw-r--r--src/libstore/gc.cc2
-rw-r--r--src/libstore/local-store.cc61
-rw-r--r--src/libstore/local-store.hh5
-rw-r--r--src/libstore/optimise-store.cc9
-rw-r--r--src/libutil/Makefile.am4
-rw-r--r--src/libutil/immutable.cc49
-rw-r--r--src/libutil/immutable.hh10
-rw-r--r--src/libutil/util.cc3
10 files changed, 76 insertions, 89 deletions
diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml
index 9560c055ba..60c119cb73 100644
--- a/doc/manual/release-notes.xml
+++ b/doc/manual/release-notes.xml
@@ -8,10 +8,17 @@
 
 <!--==================================================================-->
 
-<section xml:id="ssec-relnotes-1.3"><title>Release 1.3 (January 2, 2013)</title>
+<section xml:id="ssec-relnotes-1.3"><title>Release 1.3 (January 3, 2013)</title>
 
-<para>This is primarily a bug fix release.  It has contributions from
-Eelco Dolstra and Stuart Pernsteiner.</para>
+<para>This is primarily a bug fix release.  When this version is first
+run on Linux, it removes any immutable bits from the Nix store and
+increases the schema version of the Nix store.  (The previous release
+removed support for setting the immutable bit; this release clears any
+remaining immutable bits to make certain operations more
+efficient.)</para>
+
+<para>This release has contributions from Eelco Dolstra and Stuart
+Pernsteiner.</para>
 
 </section>
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 6ff38b0c04..75802c324e 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -7,7 +7,6 @@
 #include "local-store.hh"
 #include "util.hh"
 #include "archive.hh"
-#include "immutable.hh"
 
 #include <map>
 #include <sstream>
@@ -1383,10 +1382,8 @@ void replaceValidPath(const Path & storePath, const Path tmpPath)
        way first.  We'd better not be interrupted here, because if
        we're repairing (say) Glibc, we end up with a broken system. */
     Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % rand()).str();
-    if (pathExists(storePath)) {
-        makeMutable(storePath);
+    if (pathExists(storePath))
         rename(storePath.c_str(), oldPath.c_str());
-    }
     if (rename(tmpPath.c_str(), storePath.c_str()) == -1)
         throw SysError(format("moving `%1%' to `%2%'") % tmpPath % storePath);
     if (pathExists(oldPath))
@@ -1911,10 +1908,6 @@ void DerivationGoal::startBuilder()
             if (S_ISDIR(st.st_mode))
                 dirsInChroot[*i] = *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
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 4385e4456f..a8fa1108bf 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -1,7 +1,6 @@
 #include "globals.hh"
 #include "misc.hh"
 #include "local-store.hh"
-#include "immutable.hh"
 
 #include <boost/shared_ptr.hpp>
 
@@ -456,7 +455,6 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path)
         // if the path was not valid, need to determine the actual
         // size.
         state.bytesInvalidated += size;
-        makeMutable(path.c_str());
         // Mac OS X cannot rename directories if they are read-only.
         if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
             throw SysError(format("making `%1%' writable") % path);
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 26b4cfd8c2..87d6e6a944 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -5,7 +5,6 @@
 #include "pathlocks.hh"
 #include "worker-protocol.hh"
 #include "derivations.hh"
-#include "immutable.hh"
 
 #include <iostream>
 #include <algorithm>
@@ -25,6 +24,12 @@
 #include <sys/mount.h>
 #endif
 
+#if HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#endif
+
 #include <sqlite3.h>
 
 
@@ -292,6 +297,7 @@ LocalStore::LocalStore(bool reserveSpace)
         curSchema = getSchema();
 
         if (curSchema < 6) upgradeStore6();
+        else if (curSchema < 7) upgradeStore7();
 
         writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
 
@@ -1787,6 +1793,59 @@ void LocalStore::upgradeStore6()
 }
 
 
+#if defined(FS_IOC_SETFLAGS) && defined(FS_IOC_GETFLAGS) && defined(FS_IMMUTABLE_FL)
+
+static void makeMutable(const Path & path)
+{
+    checkInterrupt();
+
+    struct stat st = lstat(path);
+
+    if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) return;
+
+    if (S_ISDIR(st.st_mode)) {
+        Strings names = readDirectory(path);
+        foreach (Strings::iterator, i, names)
+            makeMutable(path + "/" + *i);
+    }
+
+    /* The O_NOFOLLOW is important to prevent us from changing the
+       mutable bit on the target of a symlink (which would be a
+       security hole). */
+    AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW);
+    if (fd == -1) {
+        if (errno == ELOOP) return; // it's a symlink
+        throw SysError(format("opening file `%1%'") % path);
+    }
+
+    unsigned int flags = 0, old;
+
+    /* Silently ignore errors getting/setting the immutable flag so
+       that we work correctly on filesystems that don't support it. */
+    if (ioctl(fd, FS_IOC_GETFLAGS, &flags)) return;
+    old = flags;
+    flags &= ~FS_IMMUTABLE_FL;
+    if (old == flags) return;
+    if (ioctl(fd, FS_IOC_SETFLAGS, &flags)) return;
+}
+
+/* Upgrade from schema 6 (Nix 0.15) to schema 7 (Nix >= 1.3). */
+void LocalStore::upgradeStore7()
+{
+    if (getuid() != 0) return;
+    printMsg(lvlError, "removing immutable bits from the Nix store (this may take a while)...");
+    makeMutable(settings.nixStore);
+}
+
+#else
+
+void LocalStore::upgradeStore7()
+{
+}
+
+#endif
+
+
 void LocalStore::vacuumDB()
 {
     if (sqlite3_exec(db, "vacuum;", 0, 0, 0) != SQLITE_OK)
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 82ca791a3f..2b0d713809 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -17,8 +17,8 @@ namespace nix {
 /* Nix store and database schema version.  Version 1 (or 0) was Nix <=
    0.7.  Version 2 was Nix 0.8 and 0.9.  Version 3 is Nix 0.10.
    Version 4 is Nix 0.11.  Version 5 is Nix 0.12-0.16.  Version 6 is
-   Nix 1.0. */
-const int nixSchemaVersion = 6;
+   Nix 1.0.  Version 7 is Nix 1.3. */
+const int nixSchemaVersion = 7;
 
 
 extern string drvsLogDir;
@@ -265,6 +265,7 @@ private:
     void updatePathInfo(const ValidPathInfo & info);
 
     void upgradeStore6();
+    void upgradeStore7();
     PathSet queryValidPathsOld();
     ValidPathInfo queryPathInfoOld(const Path & path);
 
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index 43b3c9b4fb..e91c2b1ce5 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -2,7 +2,6 @@
 
 #include "util.hh"
 #include "local-store.hh"
-#include "immutable.hh"
 #include "globals.hh"
 
 #include <sys/types.h>
@@ -20,7 +19,6 @@ 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);
 }
@@ -91,7 +89,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
 
     if (!pathExists(linkPath)) {
         /* Nope, create a hard link in the links directory. */
-        makeMutable(path);
         if (link(path.c_str(), linkPath.c_str()) == 0) return;
         if (errno != EEXIST)
             throw SysError(format("cannot link `%1%' to `%2%'") % linkPath % path);
@@ -123,12 +120,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
        its timestamp back to 0. */
     MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
 
-    /* If ‘linkPath’ is immutable, we can't create hard links to it,
-       so make it mutable first.  We also have to make ‘path’ mutable,
-       otherwise rename() will fail to delete it. */
-    makeMutable(path);
-    makeMutable(linkPath);
-
     Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
         % settings.nixStore % getpid() % rand()).str();
 
diff --git a/src/libutil/Makefile.am b/src/libutil/Makefile.am
index 4a3523f3be..fe896eec50 100644
--- a/src/libutil/Makefile.am
+++ b/src/libutil/Makefile.am
@@ -1,12 +1,12 @@
 pkglib_LTLIBRARIES = libutil.la
 
 libutil_la_SOURCES = util.cc hash.cc serialise.cc \
-  archive.cc xml-writer.cc immutable.cc
+  archive.cc xml-writer.cc
 
 libutil_la_LIBADD = ../boost/format/libformat.la
 
 pkginclude_HEADERS = util.hh hash.hh serialise.hh \
-  archive.hh xml-writer.hh types.hh immutable.hh
+  archive.hh xml-writer.hh types.hh
 
 if !HAVE_OPENSSL
 libutil_la_SOURCES += \
diff --git a/src/libutil/immutable.cc b/src/libutil/immutable.cc
deleted file mode 100644
index 766af49393..0000000000
--- a/src/libutil/immutable.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "config.h"
-
-#include "immutable.hh"
-#include "util.hh"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#if HAVE_LINUX_FS_H
-#include <linux/fs.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#endif
-
-namespace nix {
-
-
-void makeMutable(const Path & path)
-{
-#if defined(FS_IOC_SETFLAGS) && defined(FS_IOC_GETFLAGS) && defined(FS_IMMUTABLE_FL)
-
-    /* Don't even try if we're not root.  One day we should support
-       the CAP_LINUX_IMMUTABLE capability. */
-    if (getuid() != 0) return;
-
-    /* The O_NOFOLLOW is important to prevent us from changing the
-       mutable bit on the target of a symlink (which would be a
-       security hole). */
-    AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW);
-    if (fd == -1) {
-        if (errno == ELOOP) return; // it's a symlink
-        throw SysError(format("opening file `%1%'") % path);
-    }
-
-    unsigned int flags = 0, old;
-
-    /* Silently ignore errors getting/setting the immutable flag so
-       that we work correctly on filesystems that don't support it. */
-    if (ioctl(fd, FS_IOC_GETFLAGS, &flags)) return;
-    old = flags;
-    flags &= ~FS_IMMUTABLE_FL;
-    if (old == flags) return;
-    if (ioctl(fd, FS_IOC_SETFLAGS, &flags)) return;
-#endif
-}
-
-
-}
diff --git a/src/libutil/immutable.hh b/src/libutil/immutable.hh
deleted file mode 100644
index 8e98b76a41..0000000000
--- a/src/libutil/immutable.hh
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#include <types.hh>
-
-namespace nix {
-
-/* Make the given path mutable. */
-void makeMutable(const Path & path);
-
-}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 1308eac312..7874329c76 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -13,7 +13,6 @@
 #include <limits.h>
 
 #include "util.hh"
-#include "immutable.hh"
 
 
 extern char * * environ;
@@ -305,8 +304,6 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed)
 
     struct stat st = lstat(path);
 
-    if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) makeMutable(path);
-
     if (!S_ISDIR(st.st_mode) && st.st_nlink == 1)
         bytesFreed += st.st_blocks * 512;