summary refs log tree commit diff
path: root/nix/libstore/optimise-store.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-11-09 20:48:09 +0100
committerLudovic Courtès <ludo@gnu.org>2015-12-02 19:37:59 +0200
commite134baae774eaa78e7ae8c3d87db50170f023536 (patch)
treef1f22ba0333c47863dbb3f2c427fd37a6c310555 /nix/libstore/optimise-store.cc
parent14fb686a21d786afa699a38d20929a88be6e541d (diff)
downloadguix-e134baae774eaa78e7ae8c3d87db50170f023536.tar.gz
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.
Diffstat (limited to 'nix/libstore/optimise-store.cc')
-rw-r--r--nix/libstore/optimise-store.cc11
1 files changed, 9 insertions, 2 deletions
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