From 6e27c8b6cfcf131d5b7e45ab9f2c5cc60d5848e9 Mon Sep 17 00:00:00 2001 From: Marian Beermann Date: Fri, 10 Mar 2017 18:54:01 +0100 Subject: [PATCH] archive check: detect and fix missing all-zero replacement chunks, fixes #2180 # Conflicts: # borg/archive.py --- borg/archive.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/borg/archive.py b/borg/archive.py index df1caa6ff..3916e5622 100644 --- a/borg/archive.py +++ b/borg/archive.py @@ -984,6 +984,13 @@ class ArchiveChecker: 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. """ + def replacement_chunk(size): + data = bytes(size) + chunk_id = self.key.id_hash(data) + cdata = self.key.encrypt(data) + csize = len(cdata) + return chunk_id, size, csize, cdata + offset = 0 chunk_list = [] chunks_replaced = False @@ -1000,17 +1007,21 @@ class ArchiveChecker: 'Replacing with all-zero chunk.'.format( item[b'path'].decode('utf-8', 'surrogateescape'), offset, offset + size)) self.error_found = chunks_replaced = True - data = bytes(size) - chunk_id = self.key.id_hash(data) - cdata = self.key.encrypt(data) - csize = len(cdata) + chunk_id, size, csize, cdata = replacement_chunk(size) add_reference(chunk_id, size, csize, cdata) else: logger.info('{}: Previously missing file chunk is still missing (Byte {}-{}). ' 'It has a all-zero replacement chunk already.'.format( item[b'path'].decode('utf-8', 'surrogateescape'), offset, offset + size)) 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: if chunk_current == chunk_healthy: # normal case, all fine.