| 
					
				 | 
			
			
				@@ -1,7 +1,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from struct import Struct 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from borg.helpers import msgpack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from borg.compress import Compressor, LZ4_COMPRESSOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .helpers import msgpack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .compress import Compressor, LZ4_COMPRESSOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class RepoObj: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -19,28 +19,40 @@ class RepoObj: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Some commands write new chunks (e.g. rename) but don't take a --compression argument. This duplicates 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # the default used by those commands who do take a --compression argument. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.compressor = LZ4_COMPRESSOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.decompress = Compressor("lz4").decompress 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def id_hash(self, data: bytes) -> bytes: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return self.key.id_hash(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def format(self, id: bytes, meta: dict, data: bytes, compress: bool = True, size: int = None) -> bytes: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: bytes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        meta: dict, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        data: bytes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        compress: bool = True, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        size: int = None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ctype: int = None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        clevel: int = None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> bytes: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert isinstance(id, bytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert isinstance(meta, dict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        meta = dict(meta)  # make a copy, so call arg is not modified 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert isinstance(data, (bytes, memoryview)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert compress or size is not None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert compress or size is not None and ctype is not None and clevel is not None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if compress: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             assert size is None or size == len(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             size = len(data) if size is None else size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             data_compressed = self.compressor.compress(data)  # TODO: compressor also adds compressor type/level bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ctype = data_compressed[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            clevel = data_compressed[1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             assert isinstance(size, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert isinstance(ctype, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert isinstance(clevel, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             data_compressed = data  # is already compressed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        meta = dict(meta)  # make a copy, so call arg is not modified 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         meta["size"] = size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         meta["csize"] = len(data_compressed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # meta["ctype"] = ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # meta["clevel"] = ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        meta["ctype"] = ctype 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        meta["clevel"] = clevel 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data_encrypted = self.key.encrypt(id, data_compressed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         meta_packed = msgpack.packb(meta) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         meta_encrypted = self.key.encrypt(id, meta_packed) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -77,7 +89,12 @@ class RepoObj: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data_encrypted = obj[offs:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data_compressed = self.key.decrypt(id, data_encrypted) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if decompress: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            data = self.decompress(data_compressed)  # TODO: decompressor still needs type/level bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ctype = meta["ctype"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            clevel = meta["clevel"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            compr_hdr = bytes((ctype, clevel)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            compressor_cls, compression_level = Compressor.detect(compr_hdr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            compressor = compressor_cls(level=compression_level) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data = compressor.decompress(data_compressed)  # TODO: decompressor still needs type/level bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             self.key.assert_id(id, data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             data = data_compressed 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -93,7 +110,6 @@ class RepoObj1:  # legacy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def __init__(self, key): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.key = key 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.compressor = LZ4_COMPRESSOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.decompress = Compressor("lz4").decompress 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def id_hash(self, data: bytes) -> bytes: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return self.key.id_hash(data) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -106,7 +122,6 @@ class RepoObj1:  # legacy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert compress or size is not None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if compress: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             assert size is None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            size = len(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             data_compressed = self.compressor.compress(data)  # TODO: compressor also adds compressor type/level bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             assert isinstance(size, int) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -120,8 +135,12 @@ class RepoObj1:  # legacy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         meta = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data_compressed = self.key.decrypt(id, cdata) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         meta["csize"] = len(data_compressed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        compressor_cls, compression_level = Compressor.detect(data_compressed[:2]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        compressor = compressor_cls(level=compression_level) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        meta["ctype"] = compressor.ID[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        meta["clevel"] = compressor.level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if decompress: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            data = self.decompress(data_compressed)  # TODO: decompressor still needs type/level bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data = compressor.decompress(data_compressed)  # TODO: decompressor still needs type/level bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             self.key.assert_id(id, data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             meta["size"] = len(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else: 
			 |