diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2013-07-12 14:01:25 +0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2013-07-12 14:03:36 +0200 |
commit | aeb810b01e17d040f9592681ee271f15874dce50 (patch) | |
tree | fbf5e93aeb43f6b900f4c813ea5655385b041bdf /src | |
parent | 25a00cae5bf702b9e844b05923a9c59de9df6788 (diff) |
Garbage collector: Don't follow symlinks arbitrarily
Only indirect roots (symlinks to symlinks to the Nix store) are now
supported.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstore/gc.cc | 80 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 5 | ||||
-rw-r--r-- | src/libutil/util.cc | 9 | ||||
-rw-r--r-- | src/libutil/util.hh | 4 |
4 files changed, 53 insertions, 45 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 5c5c07e4c..37ca6be4b 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -258,8 +258,7 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds) only succeed if the owning process has died. In that case we don't care about its temporary roots. */ if (lockFile(*fd, ltWrite, false)) { - printMsg(lvlError, format("removing stale temporary roots file `%1%'") - % path); + printMsg(lvlError, format("removing stale temporary roots file `%1%'") % path); unlink(path.c_str()); writeFull(*fd, (const unsigned char *) "d", 1); continue; @@ -290,46 +289,47 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds) } -static void findRoots(StoreAPI & store, const Path & path, - bool recurseSymlinks, bool deleteStale, Roots & roots) +static void foundRoot(StoreAPI & store, + const Path & path, const Path & target, Roots & roots) { - try { + Path storePath = toStorePath(target); + if (store.isValidPath(storePath)) + roots[path] = storePath; + else + printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'") % path % storePath); +} - struct stat st; - if (lstat(path.c_str(), &st) == -1) - throw SysError(format("statting `%1%'") % path); - printMsg(lvlVomit, format("looking at `%1%'") % path); +static void findRoots(StoreAPI & store, const Path & path, Roots & roots) +{ + try { + + struct stat st = lstat(path); if (S_ISDIR(st.st_mode)) { Strings names = readDirectory(path); foreach (Strings::iterator, i, names) - findRoots(store, path + "/" + *i, recurseSymlinks, deleteStale, roots); + findRoots(store, path + "/" + *i, roots); } else if (S_ISLNK(st.st_mode)) { - Path target = absPath(readLink(path), dirOf(path)); - - if (isInStore(target)) { - debug(format("found root `%1%' in `%2%'") - % target % path); - Path storePath = toStorePath(target); - if (store.isValidPath(storePath)) - roots[path] = storePath; - else - printMsg(lvlInfo, format("skipping invalid root from `%1%' to `%2%'") - % path % storePath); - } - - else if (recurseSymlinks) { - if (pathExists(target)) - findRoots(store, target, false, deleteStale, roots); - else if (deleteStale) { - printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target); - /* Note that we only delete when recursing, i.e., - when we are still in the `gcroots' tree. We - never delete stuff outside that tree. */ - unlink(path.c_str()); + Path target = readLink(path); + if (isInStore(target)) + foundRoot(store, path, target, roots); + + /* Handle indirect roots. */ + else { + target = absPath(target, dirOf(path)); + if (!pathExists(target)) { + if (isInDir(path, settings.nixStateDir + "/" + gcRootsDir + "/auto")) { + printMsg(lvlInfo, format("removing stale link from `%1%' to `%2%'") % path % target); + unlink(path.c_str()); + } + } else { + struct stat st2 = lstat(target); + if (!S_ISLNK(st2.st_mode)) return; + Path target2 = readLink(target); + if (isInStore(target2)) foundRoot(store, path, target2, roots); } } } @@ -346,18 +346,16 @@ static void findRoots(StoreAPI & store, const Path & path, } -static Roots findRoots(StoreAPI & store, bool deleteStale) +Roots LocalStore::findRoots() { Roots roots; - Path rootsDir = canonPath((format("%1%/%2%") % settings.nixStateDir % gcRootsDir).str()); - findRoots(store, rootsDir, true, deleteStale, roots); - return roots; -} + /* Process direct roots in {gcroots,manifests,profiles}. */ + nix::findRoots(*this, settings.nixStateDir + "/" + gcRootsDir, roots); + nix::findRoots(*this, settings.nixStateDir + "/manifests", roots); + nix::findRoots(*this, settings.nixStateDir + "/profiles", roots); -Roots LocalStore::findRoots() -{ - return nix::findRoots(*this, false); + return roots; } @@ -637,7 +635,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) /* Find the roots. Since we've grabbed the GC lock, the set of permanent roots cannot increase now. */ printMsg(lvlError, format("finding garbage collector roots...")); - Roots rootMap = options.ignoreLiveness ? Roots() : nix::findRoots(*this, true); + Roots rootMap = options.ignoreLiveness ? Roots() : findRoots(); foreach (Roots::iterator, i, rootMap) state.roots.insert(i->second); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 32aaca6be..0f250a3c7 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -18,10 +18,7 @@ GCOptions::GCOptions() bool isInStore(const Path & path) { - return path[0] == '/' - && string(path, 0, settings.nixStore.size()) == settings.nixStore - && path.size() >= settings.nixStore.size() + 2 - && path[settings.nixStore.size()] == '/'; + return isInDir(path, settings.nixStore); } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index b1231e455..dad5f624b 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -148,6 +148,15 @@ string baseNameOf(const Path & path) } +bool isInDir(const Path & path, const Path & dir) +{ + return path[0] == '/' + && string(path, 0, dir.size()) == dir + && path.size() >= dir.size() + 2 + && path[dir.size()] == '/'; +} + + struct stat lstat(const Path & path) { struct stat st; diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 9caab4aa1..6c83987c5 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -45,6 +45,10 @@ Path dirOf(const Path & path); following the final `/'. */ string baseNameOf(const Path & path); +/* Check whether a given path is a descendant of the given + directory. */ +bool isInDir(const Path & path, const Path & dir); + /* Get status of `path'. */ struct stat lstat(const Path & path); |