about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstore/build.cc14
-rw-r--r--src/libstore/gc.cc48
-rw-r--r--src/libstore/pathlocks.cc2
-rw-r--r--src/libutil/util.cc10
-rw-r--r--src/libutil/util.hh1
5 files changed, 54 insertions, 21 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index a8ef9b23efaf..149cd8b09783 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1300,6 +1300,13 @@ void DerivationGoal::buildDone()
            being valid. */
         computeClosure();
 
+        /* It is now safe to delete the lock files, since all future
+           lockers will see that the output paths are valid; they will
+           not create new lock files with the same names as the old
+           (unlinked) lock files. */
+        outputLocks.setDeletion(true);
+        outputLocks.unlock();
+
     } catch (BuildError & e) {
         printMsg(lvlError, e.msg());
         outputLocks.unlock();
@@ -1987,13 +1994,6 @@ void DerivationGoal::computeClosure()
         infos.push_back(info);
     }
     worker.store.registerValidPaths(infos);
-
-    /* It is now safe to delete the lock files, since all future
-       lockers will see that the output paths are valid; they will not
-       create new lock files with the same names as the old (unlinked)
-       lock files. */
-    outputLocks.setDeletion(true);
-    outputLocks.unlock();
 }
 
 
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index e79d93723b83..feaab573ef30 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -617,27 +617,51 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
         
     } else {
         
-        printMsg(lvlError, format("reading the Nix store..."));
-        Paths entries = readDirectory(nixStore);
-
-        /* Randomise the order in which we delete entries to make the
-           collector less biased towards deleting paths that come
-           alphabetically first (e.g. /nix/store/000...).  This
-           matters when using --max-freed etc. */
-        vector<Path> entries_(entries.begin(), entries.end());
-        random_shuffle(entries_.begin(), entries_.end());
-
         if (shouldDelete(state.options.action))
             printMsg(lvlError, format("deleting garbage..."));
         else
             printMsg(lvlError, format("determining live/dead paths..."));
     
         try {
+
+            AutoCloseDir dir = opendir(nixStore.c_str());
+            if (!dir) throw SysError(format("opening directory `%1%'") % nixStore);
+
+            /* Read the store and immediately delete all paths that
+               aren't valid.  When using --max-freed etc., deleting
+               invalid paths is preferred over deleting unreachable
+               paths, since unreachable paths could become reachable
+               again.  We don't use readDirectory() here so that GCing
+               can start faster. */
+            Paths entries;
+            struct dirent * dirent;
+            while (errno = 0, dirent = readdir(dir)) {
+                checkInterrupt();
+                string name = dirent->d_name;
+                if (name == "." || name == "..") continue;
+                Path path = nixStore + "/" + name;
+                if (isValidPath(path))
+                    entries.push_back(path);
+                else
+                    tryToDelete(state, path);
+            }
+
+	    dir.close();
+
+            /* Now delete the unreachable valid paths.  Randomise the
+               order in which we delete entries to make the collector
+               less biased towards deleting paths that come
+               alphabetically first (e.g. /nix/store/000...).  This
+               matters when using --max-freed etc. */
+            vector<Path> entries_(entries.begin(), entries.end());
+            random_shuffle(entries_.begin(), entries_.end());
+
             foreach (vector<Path>::iterator, i, entries_)
-                tryToDelete(state, canonPath(nixStore + "/" + *i));
+                tryToDelete(state, *i);
+
         } catch (GCLimitReached & e) {
         }
-    }        
+    }
 }
 
 
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index d8290815c44c..645f4cd67e7e 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -16,7 +16,7 @@ int openLockFile(const Path & path, bool create)
 {
     AutoCloseFD fd;
 
-    fd = open(path.c_str(), O_RDWR | (create ? O_CREAT : 0), 0666);
+    fd = open(path.c_str(), O_RDWR | (create ? O_CREAT : 0), 0600);
     if (fd == -1 && (create || errno != ENOENT))
         throw SysError(format("opening lock file `%1%'") % path);
 
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 9adaac40d56e..0352754f592c 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -701,7 +701,7 @@ AutoCloseDir::AutoCloseDir(DIR * dir)
 
 AutoCloseDir::~AutoCloseDir()
 {
-    if (dir) closedir(dir);
+    close();
 }
 
 
@@ -717,6 +717,14 @@ AutoCloseDir::operator DIR *()
 }
 
 
+void AutoCloseDir::close()
+{
+    if (dir) {
+	closedir(dir);
+	dir = 0;
+    }
+}
+
 
 //////////////////////////////////////////////////////////////////////
 
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index f86290f31694..a1cf68e69d1c 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -223,6 +223,7 @@ public:
     ~AutoCloseDir();
     void operator =(DIR * dir);
     operator DIR *();
+    void close();
 };