mirror of https://github.com/borgbackup/borg.git
repository: add complementary index corruption test
This commit is contained in:
parent
2e067a7ae8
commit
54e023c75a
|
@ -490,6 +490,8 @@ class Repository:
|
||||||
b'storage_quota_use': self.storage_quota_use,
|
b'storage_quota_use': self.storage_quota_use,
|
||||||
}
|
}
|
||||||
integrity = {
|
integrity = {
|
||||||
|
# Integrity version started at 2, the current hints version.
|
||||||
|
# Thus, integrity version == hints version, for now.
|
||||||
b'version': 2,
|
b'version': 2,
|
||||||
}
|
}
|
||||||
transaction_id = self.io.get_segments_transaction_id()
|
transaction_id = self.io.get_segments_transaction_id()
|
||||||
|
|
|
@ -503,11 +503,6 @@ class RepositoryAuxiliaryCorruptionTestCase(RepositoryTestCaseBase):
|
||||||
self.repository.commit()
|
self.repository.commit()
|
||||||
self.repository.close()
|
self.repository.close()
|
||||||
|
|
||||||
def corrupt(self, file):
|
|
||||||
with open(file, 'r+b') as fd:
|
|
||||||
fd.seek(-1, io.SEEK_END)
|
|
||||||
fd.write(b'1')
|
|
||||||
|
|
||||||
def do_commit(self):
|
def do_commit(self):
|
||||||
with self.repository:
|
with self.repository:
|
||||||
self.repository.put(H(0), b'fox')
|
self.repository.put(H(0), b'fox')
|
||||||
|
@ -544,12 +539,42 @@ class RepositoryAuxiliaryCorruptionTestCase(RepositoryTestCaseBase):
|
||||||
with self.repository:
|
with self.repository:
|
||||||
assert len(self.repository) == 1
|
assert len(self.repository) == 1
|
||||||
|
|
||||||
|
def _corrupt_index(self):
|
||||||
|
# HashIndex is able to detect incorrect headers and file lengths,
|
||||||
|
# but on its own it can't tell if the data is correct.
|
||||||
|
index_path = os.path.join(self.repository.path, 'index.1')
|
||||||
|
with open(index_path, 'r+b') as fd:
|
||||||
|
index_data = fd.read()
|
||||||
|
# Flip one bit in a key stored in the index
|
||||||
|
corrupted_key = (int.from_bytes(H(0), 'little') ^ 1).to_bytes(32, 'little')
|
||||||
|
corrupted_index_data = index_data.replace(H(0), corrupted_key)
|
||||||
|
assert corrupted_index_data != index_data
|
||||||
|
assert len(corrupted_index_data) == len(index_data)
|
||||||
|
fd.seek(0)
|
||||||
|
fd.write(corrupted_index_data)
|
||||||
|
|
||||||
def test_index_corrupted(self):
|
def test_index_corrupted(self):
|
||||||
self.corrupt(os.path.join(self.repository.path, 'index.1'))
|
# HashIndex is able to detect incorrect headers and file lengths,
|
||||||
|
# but on its own it can't tell if the data itself is correct.
|
||||||
|
self._corrupt_index()
|
||||||
with self.repository:
|
with self.repository:
|
||||||
|
# Data corruption is detected due to mismatching checksums
|
||||||
|
# and fixed by rebuilding the index.
|
||||||
assert len(self.repository) == 1
|
assert len(self.repository) == 1
|
||||||
assert self.repository.get(H(0)) == b'foo'
|
assert self.repository.get(H(0)) == b'foo'
|
||||||
|
|
||||||
|
def test_index_corrupted_without_integrity(self):
|
||||||
|
self._corrupt_index()
|
||||||
|
integrity_path = os.path.join(self.repository.path, 'integrity.1')
|
||||||
|
os.unlink(integrity_path)
|
||||||
|
with self.repository:
|
||||||
|
# Since the corrupted key is not noticed, the repository still thinks
|
||||||
|
# it contains one key...
|
||||||
|
assert len(self.repository) == 1
|
||||||
|
with pytest.raises(Repository.ObjectNotFound):
|
||||||
|
# ... but the real, uncorrupted key is not found in the corrupted index.
|
||||||
|
self.repository.get(H(0))
|
||||||
|
|
||||||
def test_unreadable_index(self):
|
def test_unreadable_index(self):
|
||||||
index = os.path.join(self.repository.path, 'index.1')
|
index = os.path.join(self.repository.path, 'index.1')
|
||||||
os.unlink(index)
|
os.unlink(index)
|
||||||
|
@ -558,13 +583,16 @@ class RepositoryAuxiliaryCorruptionTestCase(RepositoryTestCaseBase):
|
||||||
self.do_commit()
|
self.do_commit()
|
||||||
|
|
||||||
def test_unknown_integrity_version(self):
|
def test_unknown_integrity_version(self):
|
||||||
|
# For now an unknown integrity data version is ignored and not an error.
|
||||||
integrity_path = os.path.join(self.repository.path, 'integrity.1')
|
integrity_path = os.path.join(self.repository.path, 'integrity.1')
|
||||||
with open(integrity_path, 'r+b') as fd:
|
with open(integrity_path, 'r+b') as fd:
|
||||||
msgpack.pack({
|
msgpack.pack({
|
||||||
|
# Borg only understands version 2
|
||||||
b'version': 4.7,
|
b'version': 4.7,
|
||||||
}, fd)
|
}, fd)
|
||||||
fd.truncate()
|
fd.truncate()
|
||||||
with self.repository:
|
with self.repository:
|
||||||
|
# No issues accessing the repository
|
||||||
assert len(self.repository) == 1
|
assert len(self.repository) == 1
|
||||||
assert self.repository.get(H(0)) == b'foo'
|
assert self.repository.get(H(0)) == b'foo'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue