about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-01-29T11·53+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-01-29T11·53+0000
commitad529fb89fb34bea9762eccfc9c2ee6f1f2865c0 (patch)
treee24066a331ca32fa4436a539c0538c3a96a7ece7
parentfdcaf37361126793a1416ef5b348e5bf2f0fd1a0 (diff)
* Don't consider a store path valid if its info file exists but is
  zero bytes long.  That makes Nix more robust in case of crashes
  (especially on ext4).

-rw-r--r--src/libstore/local-store.cc40
1 files changed, 36 insertions, 4 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 135446fe11c4..93ce8c047a7d 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -390,6 +390,9 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
 
     assertStorePath(path);
 
+    if (!isValidPath(path))
+        throw Error(format("path `%1%' is not valid") % path);
+
     std::map<Path, ValidPathInfo>::iterator lookup = pathInfoCache.find(path);
     if (lookup != pathInfoCache.end()) return lookup->second;
     
@@ -404,7 +407,11 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
 
     foreach (Strings::iterator, i, lines) {
         string::size_type p = i->find(':');
-        if (p == string::npos) continue; /* bad line */
+        if (p == string::npos) {
+            if (!ignoreErrors)
+                throw Error(format("corrupt line in `%1%': %2%") % infoFile % *i);
+            continue; /* bad line */
+        }
         string name(*i, 0, p);
         string value(*i, p + 2);
         if (name == "References") {
@@ -435,7 +442,22 @@ bool LocalStore::isValidPath(const Path & path)
     /* Files in the info directory starting with a `.' are temporary
        files. */
     if (baseNameOf(path).at(0) == '.') return false;
-    return pathExists(infoFileFor(path));
+
+    /* A path is valid if its info file exists and has a non-zero
+       size.  (The non-zero size restriction is to be robust to
+       certain kinds of filesystem corruption, particularly with
+       ext4.) */
+    Path infoFile = infoFileFor(path);
+
+    struct stat st;
+    if (lstat(infoFile.c_str(), &st)) {
+        if (errno == ENOENT) return false;
+        throw SysError(format("getting status of `%1%'") % infoFile);
+    }
+
+    if (st.st_size == 0) return false;
+    
+    return true;
 }
 
 
@@ -1028,8 +1050,18 @@ void LocalStore::verifyStore(bool checkContents)
         } else if (!pathExists(*i)) {
             printMsg(lvlError, format("path `%1%' disappeared") % *i);
             invalidatePath(*i);
-        } else
-            validPaths.insert(*i);
+        } else {
+            Path infoFile = infoFileFor(*i);
+            struct stat st;
+            if (lstat(infoFile.c_str(), &st))
+                throw SysError(format("getting status of `%1%'") % infoFile);
+            if (st.st_size == 0) {
+                printMsg(lvlError, format("removing corrupt info file `%1%'") % infoFile);
+                if (unlink(infoFile.c_str()) == -1)
+                    throw SysError(format("unlinking `%1%'") % infoFile);
+            }
+            else validPaths.insert(*i);
+        }
     }