aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-01-29 11:53:58 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-01-29 11:53:58 +0000
commitad529fb89fb34bea9762eccfc9c2ee6f1f2865c0 (patch)
treee24066a331ca32fa4436a539c0538c3a96a7ece7 /src/libstore
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).
Diffstat (limited to 'src/libstore')
-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 135446fe1..93ce8c047 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);
+ }
}