aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/gc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/gc.cc')
-rw-r--r--src/libstore/gc.cc120
1 files changed, 64 insertions, 56 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index c9e51f447..e5217c9b8 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -91,12 +91,6 @@ void LocalStore::addIndirectRoot(const Path & path)
}
-typedef std::map<Path, Path> Roots;
-
-
-static void findRoots(Roots & roots, bool ignoreUnreadable);
-
-
Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
bool indirect, bool allowOutsideRootsDir)
{
@@ -122,17 +116,17 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
createSymlink(gcRoot, storePath, false);
- /* Check that the root can be found by the garbage collector. */
- Roots roots;
- findRoots(roots, true);
- if (roots.find(gcRoot) == roots.end())
- printMsg(lvlError,
- format(
- "warning: the garbage collector does not find `%1%' as a root; "
- "therefore, `%2%' might be removed by the garbage collector")
- % gcRoot % storePath);
}
+ /* Check that the root can be found by the garbage collector. */
+ Roots roots = store->findRoots();
+ if (roots.find(gcRoot) == roots.end())
+ printMsg(lvlError,
+ format(
+ "warning: the garbage collector does not find `%1%' as a root; "
+ "therefore, `%2%' might be removed by the garbage collector")
+ % gcRoot % storePath);
+
/* Grab the global GC root, causing us to block while a GC is in
progress. This prevents the set of permanent roots from
increasing while a GC is in progress. */
@@ -308,58 +302,73 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
static void findRoots(const Path & path, bool recurseSymlinks,
- bool ignoreUnreadable, Roots & roots)
+ bool deleteStale, Roots & roots)
{
- struct stat st;
- if (lstat(path.c_str(), &st) == -1)
- throw SysError(format("statting `%1%'") % path);
-
- printMsg(lvlVomit, format("looking at `%1%'") % path);
+ try {
+
+ struct stat st;
+ if (lstat(path.c_str(), &st) == -1)
+ throw SysError(format("statting `%1%'") % path);
- if (S_ISDIR(st.st_mode)) {
- Strings names = readDirectory(path);
- for (Strings::iterator i = names.begin(); i != names.end(); ++i)
- findRoots(path + "/" + *i, recurseSymlinks, ignoreUnreadable, roots);
- }
+ printMsg(lvlVomit, format("looking at `%1%'") % path);
- 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);
+ if (S_ISDIR(st.st_mode)) {
+ Strings names = readDirectory(path);
+ for (Strings::iterator i = names.begin(); i != names.end(); ++i)
+ findRoots(path + "/" + *i, recurseSymlinks, deleteStale, roots);
}
- else if (recurseSymlinks) {
- struct stat st2;
- if (lstat(target.c_str(), &st2) == 0)
- findRoots(target, false, ignoreUnreadable, roots);
- else if (ignoreUnreadable && errno == EACCES)
- /* ignore */ ;
- else if (errno == ENOENT || errno == ENOTDIR) {
- 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());
+ 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(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());
+ }
}
- else
- throw SysError(format("statting `%1%'") % target);
}
+
+ }
+
+ catch (SysError & e) {
+ /* We only ignore permanent failures. */
+ if (e.errNo == EACCES || e.errNo == ENOENT || e.errNo == ENOTDIR)
+ printMsg(lvlInfo, format("cannot read potential root `%1%'") % path);
+ else
+ throw;
}
}
-static void findRoots(Roots & roots, bool ignoreUnreadable)
+static Roots findRoots(bool deleteStale)
{
+ Roots roots;
Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % gcRootsDir).str());
- findRoots(rootsDir, true, ignoreUnreadable, roots);
+ findRoots(rootsDir, true, deleteStale, roots);
+ return roots;
+}
+
+
+Roots LocalStore::findRoots()
+{
+ return nix::findRoots(false);
}
@@ -437,8 +446,7 @@ void collectGarbage(GCAction action, const PathSet & pathsToDelete,
/* Find the roots. Since we've grabbed the GC lock, the set of
permanent roots cannot increase now. */
- Roots rootMap;
- findRoots(rootMap, false);
+ Roots rootMap = ignoreLiveness ? Roots() : findRoots(true);
PathSet roots;
for (Roots::iterator i = rootMap.begin(); i != rootMap.end(); ++i)