Browse Source

Merge pull request #2181 from ThomasWaldmann/fix-2180

archive check: detect and fix missing replacement chunks, fixes #2180
TW 8 years ago
parent
commit
268d74bb43
1 changed files with 16 additions and 5 deletions
  1. 16 5
      src/borg/archive.py

+ 16 - 5
src/borg/archive.py

@@ -1246,6 +1246,13 @@ class ArchiveChecker:
             Missing file chunks will be replaced with new chunks of the same length containing all zeros.
             Missing file chunks will be replaced with new chunks of the same length containing all zeros.
             If a previously missing file chunk re-appears, the replacement chunk is replaced by the correct one.
             If a previously missing file chunk re-appears, the replacement chunk is replaced by the correct one.
             """
             """
+            def replacement_chunk(size):
+                data = bytes(size)
+                chunk_id = self.key.id_hash(data)
+                cdata = self.key.encrypt(Chunk(data))
+                csize = len(cdata)
+                return chunk_id, size, csize, cdata
+
             offset = 0
             offset = 0
             chunk_list = []
             chunk_list = []
             chunks_replaced = False
             chunks_replaced = False
@@ -1261,16 +1268,20 @@ class ArchiveChecker:
                         logger.error('{}: New missing file chunk detected (Byte {}-{}). '
                         logger.error('{}: New missing file chunk detected (Byte {}-{}). '
                                      'Replacing with all-zero chunk.'.format(item.path, offset, offset + size))
                                      'Replacing with all-zero chunk.'.format(item.path, offset, offset + size))
                         self.error_found = chunks_replaced = True
                         self.error_found = chunks_replaced = True
-                        data = bytes(size)
-                        chunk_id = self.key.id_hash(data)
-                        cdata = self.key.encrypt(Chunk(data))
-                        csize = len(cdata)
+                        chunk_id, size, csize, cdata = replacement_chunk(size)
                         add_reference(chunk_id, size, csize, cdata)
                         add_reference(chunk_id, size, csize, cdata)
                     else:
                     else:
                         logger.info('{}: Previously missing file chunk is still missing (Byte {}-{}). It has a '
                         logger.info('{}: Previously missing file chunk is still missing (Byte {}-{}). It has a '
                                     'all-zero replacement chunk already.'.format(item.path, offset, offset + size))
                                     'all-zero replacement chunk already.'.format(item.path, offset, offset + size))
                         chunk_id, size, csize = chunk_current
                         chunk_id, size, csize = chunk_current
-                        add_reference(chunk_id, size, csize)
+                        if chunk_id in self.chunks:
+                            add_reference(chunk_id, size, csize)
+                        else:
+                            logger.warning('{}: Missing all-zero replacement chunk detected (Byte {}-{}). '
+                                           'Generating new replacement chunk.'.format(item.path, offset, offset + size))
+                            self.error_found = chunks_replaced = True
+                            chunk_id, size, csize, cdata = replacement_chunk(size)
+                            add_reference(chunk_id, size, csize, cdata)
                 else:
                 else:
                     if chunk_current == chunk_healthy:
                     if chunk_current == chunk_healthy:
                         # normal case, all fine.
                         # normal case, all fine.