From def5160b614a59a0aa96fe2252e3daa00146e061 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 3 Jan 2013 12:59:23 +0100 Subject: 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. --- src/libstore/build.cc | 9 +------ src/libstore/gc.cc | 2 -- src/libstore/local-store.cc | 61 +++++++++++++++++++++++++++++++++++++++++- src/libstore/local-store.hh | 5 ++-- src/libstore/optimise-store.cc | 9 ------- 5 files changed, 64 insertions(+), 22 deletions(-) (limited to 'src/libstore') 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 #include @@ -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 @@ -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 #include @@ -25,6 +24,12 @@ #include #endif +#if HAVE_LINUX_FS_H +#include +#include +#include +#endif + #include @@ -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 @@ -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(); -- cgit 1.4.1