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/local-store.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) (limited to 'src/libstore/local-store.cc') diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 26b4cfd8c234..87d6e6a94449 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) -- cgit 1.4.1