[PATCH 2 of 4 stable v2] largefiles: check hash of files in the store before copying to working dir

Mads Kiilerich mads at kiilerich.com
Fri Oct 23 14:27:56 CDT 2015


# HG changeset patch
# User Mads Kiilerich <madski at unity3d.com>
# Date 1445628449 -7200
#      Fri Oct 23 21:27:29 2015 +0200
# Branch stable
# Node ID 4b974ff528d704a503e8b22f00126935cabb80a2
# Parent  dcb31859ffc73331a3ea337ac5df5001a75d57a5
largefiles: check hash of files in the store before copying to working dir

If the store somehow got corrupted, users could end up in weird situations that
were very hard to recover from or lead to propagation of the corruption.

Instead, spend the extra time checking the hash when copying to the working
directory. If it doesn't match, emit a warning, and don't put wrong content in
the working directory.

diff --git a/hgext/largefiles/lfutil.py b/hgext/largefiles/lfutil.py
--- a/hgext/largefiles/lfutil.py
+++ b/hgext/largefiles/lfutil.py
@@ -10,7 +10,6 @@
 
 import os
 import platform
-import shutil
 import stat
 import copy
 
@@ -207,7 +206,15 @@ def copyfromcache(repo, hash, filename):
     util.makedirs(os.path.dirname(repo.wjoin(filename)))
     # The write may fail before the file is fully written, but we
     # don't use atomic writes in the working copy.
-    shutil.copy(path, repo.wjoin(filename))
+    dest = repo.wjoin(filename)
+    with open(path, 'rb') as srcfd:
+        with open(dest, 'wb') as destfd:
+            gothash = copyandhash(srcfd, destfd)
+    if gothash != hash:
+        repo.ui.warn(_('%s: data corruption in %s with hash %s\n')
+                     % (filename, path, gothash))
+        util.unlink(dest)
+        return False
     return True
 
 def copytostore(repo, rev, file, uploaded=False):
diff --git a/tests/test-largefiles-cache.t b/tests/test-largefiles-cache.t
--- a/tests/test-largefiles-cache.t
+++ b/tests/test-largefiles-cache.t
@@ -191,13 +191,12 @@ Inject corruption into the largefiles st
   e2fb5f2139d086ded2cb600d5a91a196e76bf020
   $ mv .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 ..
   $ echo corruption > .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020
-(the following update will put the corrupted file into the working directory
-where it will show up as a change)
   $ hg up -C
   getting changed largefiles
-  1 largefiles updated, 0 removed
+  large: data corruption in $TESTTMP/src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 with hash 6a7bb2556144babe3899b25e5428123735bb1e27
+  0 largefiles updated, 0 removed
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg st
-  M large
+  ! large
   ? z
   $ rm .hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020


More information about the Mercurial-devel mailing list