optimizePath(): Detect some .links corruption

If automatic store optimisation is enabled, and a hard-linked file in
the store gets corrupted, then the corresponding .links entry will
also be corrupted. In that case, trying to repair with --repair or
--repair-path won't work, because the new "good" file will be replaced
by a hard link to the corrupted file. We can catch most of these cases
by doing a sanity-check on the file sizes.
This commit is contained in:
Eelco Dolstra 2015-11-09 20:48:09 +01:00
parent 7759a56bed
commit 4384bbd2e1

View file

@ -120,9 +120,9 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
return; return;
} }
/* This can still happen on top-level files */ /* This can still happen on top-level files. */
if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) { if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) {
printMsg(lvlDebug, format("%1% is already linked, with %2% other file(s).") % path % (st.st_nlink - 2)); printMsg(lvlDebug, format("%1% is already linked, with %2% other file(s)") % path % (st.st_nlink - 2));
return; return;
} }
@ -141,6 +141,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
/* Check if this is a known hash. */ /* Check if this is a known hash. */
Path linkPath = linksDir + "/" + printHash32(hash); Path linkPath = linksDir + "/" + printHash32(hash);
retry:
if (!pathExists(linkPath)) { if (!pathExists(linkPath)) {
/* Nope, create a hard link in the links directory. */ /* Nope, create a hard link in the links directory. */
if (link(path.c_str(), linkPath.c_str()) == 0) { if (link(path.c_str(), linkPath.c_str()) == 0) {
@ -164,6 +165,12 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
return; return;
} }
if (st.st_size != stLink.st_size) {
printMsg(lvlError, format("removing corrupted link %1%") % linkPath);
unlink(linkPath.c_str());
goto retry;
}
printMsg(lvlTalkative, format("linking %1% to %2%") % path % linkPath); printMsg(lvlTalkative, format("linking %1% to %2%") % path % linkPath);
/* Make the containing directory writable, but only if it's not /* Make the containing directory writable, but only if it's not