* 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).
This commit is contained in:
parent
fdcaf37361
commit
ad529fb89f
1 changed files with 36 additions and 4 deletions
|
@ -390,6 +390,9 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
|
||||||
|
|
||||||
assertStorePath(path);
|
assertStorePath(path);
|
||||||
|
|
||||||
|
if (!isValidPath(path))
|
||||||
|
throw Error(format("path `%1%' is not valid") % path);
|
||||||
|
|
||||||
std::map<Path, ValidPathInfo>::iterator lookup = pathInfoCache.find(path);
|
std::map<Path, ValidPathInfo>::iterator lookup = pathInfoCache.find(path);
|
||||||
if (lookup != pathInfoCache.end()) return lookup->second;
|
if (lookup != pathInfoCache.end()) return lookup->second;
|
||||||
|
|
||||||
|
@ -404,7 +407,11 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path, bool ignoreErrors)
|
||||||
|
|
||||||
foreach (Strings::iterator, i, lines) {
|
foreach (Strings::iterator, i, lines) {
|
||||||
string::size_type p = i->find(':');
|
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 name(*i, 0, p);
|
||||||
string value(*i, p + 2);
|
string value(*i, p + 2);
|
||||||
if (name == "References") {
|
if (name == "References") {
|
||||||
|
@ -435,7 +442,22 @@ bool LocalStore::isValidPath(const Path & path)
|
||||||
/* Files in the info directory starting with a `.' are temporary
|
/* Files in the info directory starting with a `.' are temporary
|
||||||
files. */
|
files. */
|
||||||
if (baseNameOf(path).at(0) == '.') return false;
|
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)) {
|
} else if (!pathExists(*i)) {
|
||||||
printMsg(lvlError, format("path `%1%' disappeared") % *i);
|
printMsg(lvlError, format("path `%1%' disappeared") % *i);
|
||||||
invalidatePath(*i);
|
invalidatePath(*i);
|
||||||
} else
|
} else {
|
||||||
validPaths.insert(*i);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue