diff --git a/src/borg/repoobj.py b/src/borg/repoobj.py index ad8e52d6f..f2a57f95a 100644 --- a/src/borg/repoobj.py +++ b/src/borg/repoobj.py @@ -13,11 +13,14 @@ AUTHENTICATED_NO_KEY = "authenticated_no_key" in workarounds OBJ_MAGIC = b"BORG_OBJ" OBJ_VERSION = 0x01 +# Fixed header size per blob: OBJ_MAGIC(8) + version(1) + chunk_id(32) + meta_size(4) + data_size(4) +REPOOBJ_HEADER_SIZE = 49 + class RepoObj: - # Object header: magic (8b), format version (1b), meta size (4b), data size (4b). - obj_header = Struct("<8sBII") - ObjHeader = namedtuple("ObjHeader", "magic version meta_size data_size") + # Object header: magic (8b), format version (1b), chunk_id (32b), meta size (4b), data size (4b). + obj_header = Struct("<8sB32sII") + ObjHeader = namedtuple("ObjHeader", "magic version chunk_id meta_size data_size") @classmethod def extract_crypted_data(cls, data: bytes) -> bytes: @@ -72,7 +75,7 @@ class RepoObj: data_encrypted = self.key.encrypt(id, data_compressed) meta_packed = msgpack.packb(meta) meta_encrypted = self.key.encrypt(id, meta_packed) - hdr = self.ObjHeader(OBJ_MAGIC, OBJ_VERSION, len(meta_encrypted), len(data_encrypted)) + hdr = self.ObjHeader(OBJ_MAGIC, OBJ_VERSION, id, len(meta_encrypted), len(data_encrypted)) hdr_packed = self.obj_header.pack(*hdr) return hdr_packed + meta_encrypted + data_encrypted diff --git a/src/borg/testsuite/repository_test.py b/src/borg/testsuite/repository_test.py index 5e15ec794..becdb3635 100644 --- a/src/borg/testsuite/repository_test.py +++ b/src/borg/testsuite/repository_test.py @@ -53,9 +53,9 @@ def reopen(repository, exclusive: bool | None = True, create=False): ) -def fchunk(data, meta=b""): +def fchunk(data, meta=b"", chunk_id=b"\x00" * 32): # Format chunk: create a raw chunk that has a valid RepoObj layout, but does not use encryption or compression. - hdr = RepoObj.obj_header.pack(OBJ_MAGIC, OBJ_VERSION, len(meta), len(data)) + hdr = RepoObj.obj_header.pack(OBJ_MAGIC, OBJ_VERSION, chunk_id, len(meta), len(data)) assert isinstance(data, bytes) chunk = hdr + meta + data return chunk @@ -65,7 +65,7 @@ def pchunk(chunk): # Parse chunk: extract data and metadata from a raw chunk made by fchunk. hdr_size = RepoObj.obj_header.size hdr = chunk[:hdr_size] - meta_size, data_size = RepoObj.obj_header.unpack(hdr)[2:4] + meta_size, data_size = RepoObj.obj_header.unpack(hdr)[3:5] meta = chunk[hdr_size : hdr_size + meta_size] data = chunk[hdr_size + meta_size : hdr_size + meta_size + data_size] return data, meta @@ -97,7 +97,7 @@ def test_basic_operations(repo_fixtures, request): def test_read_data(repo_fixtures, request): with get_repository_from_fixture(repo_fixtures, request) as repository: meta, data = b"meta", b"data" - hdr = RepoObj.obj_header.pack(OBJ_MAGIC, OBJ_VERSION, len(meta), len(data)) + hdr = RepoObj.obj_header.pack(OBJ_MAGIC, OBJ_VERSION, H(0), len(meta), len(data)) chunk_complete = hdr + meta + data chunk_short = hdr + meta repository.put(H(0), chunk_complete)