daemon: optimizePath: Detect some .links corruptions.

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 committed by Ludovic Courtès
parent 14fb686a21
commit e134baae77
1 changed files with 9 additions and 2 deletions

View File

@ -120,7 +120,7 @@ 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,7 +165,13 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa
return; return;
} }
printMsg(lvlTalkative, format("linking `%1%' to `%2%'") % path % linkPath); 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);
/* Make the containing directory writable, but only if it's not /* Make the containing directory writable, but only if it's not
the store itself (we don't want or need to mess with its the store itself (we don't want or need to mess with its