From e134baae774eaa78e7ae8c3d87db50170f023536 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Nov 2015 20:48:09 +0100 Subject: 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. --- nix/libstore/optimise-store.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'nix/libstore/optimise-store.cc') diff --git a/nix/libstore/optimise-store.cc b/nix/libstore/optimise-store.cc index c62b8e451b..d7508b025e 100644 --- a/nix/libstore/optimise-store.cc +++ b/nix/libstore/optimise-store.cc @@ -120,7 +120,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa 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)) { printMsg(lvlDebug, format("`%1%' is already linked, with %2% other file(s).") % path % (st.st_nlink - 2)); return; @@ -141,6 +141,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa /* Check if this is a known hash. */ Path linkPath = linksDir + "/" + printHash32(hash); + retry: if (!pathExists(linkPath)) { /* Nope, create a hard link in the links directory. */ if (link(path.c_str(), linkPath.c_str()) == 0) { @@ -164,7 +165,13 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa 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 the store itself (we don't want or need to mess with its -- cgit v1.2.3