about summary refs log tree commit diff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/gc.cc27
-rw-r--r--src/libstore/gc.hh5
2 files changed, 22 insertions, 10 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index cb808b6d1b68..c02f59f2cca6 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -303,8 +303,8 @@ static Paths topoSort(const PathSet & paths)
 }
 
 
-void collectGarbage(GCAction action, PathSet & result,
-    unsigned long long & bytesFreed)
+void collectGarbage(GCAction action, const PathSet & pathsToDelete,
+    PathSet & result, unsigned long long & bytesFreed)
 {
     result.clear();
     bytesFreed = 0;
@@ -398,17 +398,26 @@ void collectGarbage(GCAction action, PathSet & result,
     
     /* Read the Nix store directory to find all currently existing
        paths. */
-    Paths storePaths = readDirectory(nixStore);
-    PathSet storePaths2;
-    for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i)
-        storePaths2.insert(canonPath(nixStore + "/" + *i));
+    PathSet storePathSet;
+    if (action != gcDeleteSpecific) {
+        Paths entries = readDirectory(nixStore);
+        for (Paths::iterator i = entries.begin(); i != entries.end(); ++i)
+            storePathSet.insert(canonPath(nixStore + "/" + *i));
+    } else {
+        for (PathSet::iterator i = pathsToDelete.begin();
+             i != pathsToDelete.end(); ++i)
+        {
+            assertStorePath(*i);
+            storePathSet.insert(*i);
+        }
+    }
 
     /* Topologically sort them under the `referrers' relation.  That
        is, a < b iff a is in referrers(b).  This gives us the order in
        which things can be deleted safely. */
     /* !!! when we have multiple output paths per derivation, this
        will not work anymore because we get cycles. */
-    storePaths = topoSort(storePaths2);
+    Paths storePaths = topoSort(storePathSet);
 
     /* Try to delete store paths in the topologically sorted order. */
     for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i) {
@@ -416,6 +425,8 @@ void collectGarbage(GCAction action, PathSet & result,
         debug(format("considering deletion of `%1%'") % *i);
         
         if (livePaths.find(*i) != livePaths.end()) {
+            if (action == gcDeleteSpecific)
+                throw Error(format("cannot delete path `%1%' since it is still alive") % *i);
             debug(format("live path `%1%'") % *i);
             continue;
         }
@@ -430,7 +441,7 @@ void collectGarbage(GCAction action, PathSet & result,
 
         AutoCloseFD fdLock;
 
-        if (action == gcDeleteDead) {
+        if (action == gcDeleteDead || action == gcDeleteSpecific) {
 
             /* Only delete a lock file if we can acquire a write lock
                on it.  That means that it's either stale, or the
diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh
index eb1858729037..b05d88f93088 100644
--- a/src/libstore/gc.hh
+++ b/src/libstore/gc.hh
@@ -10,6 +10,7 @@ typedef enum {
     gcReturnLive,
     gcReturnDead,
     gcDeleteDead,
+    gcDeleteSpecific,
 } GCAction;
 
 /* If `action' is set to `gcReturnRoots', find and return the set of
@@ -19,8 +20,8 @@ typedef enum {
    closure of) the roots.  If `action' is `gcReturnDead', return the
    set of paths not reachable from the roots.  If `action' is
    `gcDeleteDead', actually delete the latter set. */
-void collectGarbage(GCAction action, PathSet & result,
-    unsigned long long & bytesFreed);
+void collectGarbage(GCAction action, const PathSet & pathsToDelete,
+    PathSet & result, unsigned long long & bytesFreed);
 
 /* Register a temporary GC root.  This root will automatically
    disappear when this process exits.  WARNING: this function should