diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2010-01-29 11:53:58 +0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2010-01-29 11:53:58 +0000 |
commit | ad529fb89fb34bea9762eccfc9c2ee6f1f2865c0 (patch) | |
tree | e24066a331ca32fa4436a539c0538c3a96a7ece7 /src/libstore | |
parent | fdcaf37361126793a1416ef5b348e5bf2f0fd1a0 (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.cc | 40 |
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); + } } |