@@ -76,6 +76,16 @@ def getFirstBlockFileId(block_dir_path):
7676 blkId = int (firstBlkFn [3 :8 ])
7777 return blkId
7878
79+ def read_xor_key (blocks_path ):
80+ NUM_XOR_BYTES = 8 # From InitBlocksdirXorKey::xor_key.size()
81+ try :
82+ xor_filename = os .path .join (blocks_path , "xor.dat" )
83+ with open (xor_filename , "rb" ) as xor_file :
84+ return xor_file .read (NUM_XOR_BYTES )
85+ # support also blockdirs created with pre-v28 versions, where no xor key exists yet
86+ except FileNotFoundError :
87+ return bytes ([0 ] * NUM_XOR_BYTES )
88+
7989# Block header and extent on disk
8090BlockExtent = namedtuple ('BlockExtent' , ['fn' , 'offset' , 'inhdr' , 'blkhdr' , 'size' ])
8191
@@ -95,6 +105,7 @@ def __init__(self, settings, blkindex, blkmap):
95105 self .outFname = None
96106 self .blkCountIn = 0
97107 self .blkCountOut = 0
108+ self .xor_key = read_xor_key (self .settings ['input' ])
98109
99110 self .lastDate = datetime .datetime (2000 , 1 , 1 )
100111 self .highTS = 1408893517 - 315360000
@@ -113,6 +124,13 @@ def __init__(self, settings, blkindex, blkmap):
113124 self .outOfOrderData = {}
114125 self .outOfOrderSize = 0 # running total size for items in outOfOrderData
115126
127+ def read_xored (self , f , size ):
128+ offset = f .tell ()
129+ data = bytearray (f .read (size ))
130+ for i in range (len (data )):
131+ data [i ] ^= self .xor_key [(i + offset ) % len (self .xor_key )]
132+ return bytes (data )
133+
116134 def writeBlock (self , inhdr , blk_hdr , rawblock ):
117135 blockSizeOnDisk = len (inhdr ) + len (blk_hdr ) + len (rawblock )
118136 if not self .fileOutput and ((self .outsz + blockSizeOnDisk ) > self .maxOutSz ):
@@ -165,7 +183,7 @@ def fetchBlock(self, extent):
165183 '''Fetch block contents from disk given extents'''
166184 with open (self .inFileName (extent .fn ), "rb" ) as f :
167185 f .seek (extent .offset )
168- return f . read ( extent .size )
186+ return self . read_xored ( f , extent .size )
169187
170188 def copyOneBlock (self ):
171189 '''Find the next block to be written in the input, and copy it to the output.'''
@@ -190,7 +208,7 @@ def run(self):
190208 print ("Premature end of block data" )
191209 return
192210
193- inhdr = self .inF . read ( 8 )
211+ inhdr = self .read_xored ( self . inF , 8 )
194212 if (not inhdr or (inhdr [0 ] == "\0 " )):
195213 self .inF .close ()
196214 self .inF = None
@@ -207,7 +225,7 @@ def run(self):
207225 inLenLE = inhdr [4 :]
208226 su = struct .unpack ("<I" , inLenLE )
209227 inLen = su [0 ] - 80 # length without header
210- blk_hdr = self .inF . read ( 80 )
228+ blk_hdr = self .read_xored ( self . inF , 80 )
211229 inExtent = BlockExtent (self .inFn , self .inF .tell (), inhdr , blk_hdr , inLen )
212230
213231 self .hash_str = calc_hash_str (blk_hdr )
@@ -224,7 +242,7 @@ def run(self):
224242
225243 if self .blkCountOut == blkHeight :
226244 # If in-order block, just copy
227- rawblock = self .inF . read ( inLen )
245+ rawblock = self .read_xored ( self . inF , inLen )
228246 self .writeBlock (inhdr , blk_hdr , rawblock )
229247
230248 # See if we can catch up to prior out-of-order blocks
@@ -237,7 +255,7 @@ def run(self):
237255 # If there is space in the cache, read the data
238256 # Reading the data in file sequence instead of seeking and fetching it later is preferred,
239257 # but we don't want to fill up memory
240- self .outOfOrderData [blkHeight ] = self .inF . read ( inLen )
258+ self .outOfOrderData [blkHeight ] = self .read_xored ( self . inF , inLen )
241259 self .outOfOrderSize += inLen
242260 else : # If no space in cache, seek forward
243261 self .inF .seek (inLen , os .SEEK_CUR )
0 commit comments