@@ -76,6 +76,16 @@ def getFirstBlockFileId(block_dir_path):
76
76
blkId = int (firstBlkFn [3 :8 ])
77
77
return blkId
78
78
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
+
79
89
# Block header and extent on disk
80
90
BlockExtent = namedtuple ('BlockExtent' , ['fn' , 'offset' , 'inhdr' , 'blkhdr' , 'size' ])
81
91
@@ -95,6 +105,7 @@ def __init__(self, settings, blkindex, blkmap):
95
105
self .outFname = None
96
106
self .blkCountIn = 0
97
107
self .blkCountOut = 0
108
+ self .xor_key = read_xor_key (self .settings ['input' ])
98
109
99
110
self .lastDate = datetime .datetime (2000 , 1 , 1 )
100
111
self .highTS = 1408893517 - 315360000
@@ -113,6 +124,13 @@ def __init__(self, settings, blkindex, blkmap):
113
124
self .outOfOrderData = {}
114
125
self .outOfOrderSize = 0 # running total size for items in outOfOrderData
115
126
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
+
116
134
def writeBlock (self , inhdr , blk_hdr , rawblock ):
117
135
blockSizeOnDisk = len (inhdr ) + len (blk_hdr ) + len (rawblock )
118
136
if not self .fileOutput and ((self .outsz + blockSizeOnDisk ) > self .maxOutSz ):
@@ -165,7 +183,7 @@ def fetchBlock(self, extent):
165
183
'''Fetch block contents from disk given extents'''
166
184
with open (self .inFileName (extent .fn ), "rb" ) as f :
167
185
f .seek (extent .offset )
168
- return f . read ( extent .size )
186
+ return self . read_xored ( f , extent .size )
169
187
170
188
def copyOneBlock (self ):
171
189
'''Find the next block to be written in the input, and copy it to the output.'''
@@ -190,7 +208,7 @@ def run(self):
190
208
print ("Premature end of block data" )
191
209
return
192
210
193
- inhdr = self .inF . read ( 8 )
211
+ inhdr = self .read_xored ( self . inF , 8 )
194
212
if (not inhdr or (inhdr [0 ] == "\0 " )):
195
213
self .inF .close ()
196
214
self .inF = None
@@ -207,7 +225,7 @@ def run(self):
207
225
inLenLE = inhdr [4 :]
208
226
su = struct .unpack ("<I" , inLenLE )
209
227
inLen = su [0 ] - 80 # length without header
210
- blk_hdr = self .inF . read ( 80 )
228
+ blk_hdr = self .read_xored ( self . inF , 80 )
211
229
inExtent = BlockExtent (self .inFn , self .inF .tell (), inhdr , blk_hdr , inLen )
212
230
213
231
self .hash_str = calc_hash_str (blk_hdr )
@@ -224,7 +242,7 @@ def run(self):
224
242
225
243
if self .blkCountOut == blkHeight :
226
244
# If in-order block, just copy
227
- rawblock = self .inF . read ( inLen )
245
+ rawblock = self .read_xored ( self . inF , inLen )
228
246
self .writeBlock (inhdr , blk_hdr , rawblock )
229
247
230
248
# See if we can catch up to prior out-of-order blocks
@@ -237,7 +255,7 @@ def run(self):
237
255
# If there is space in the cache, read the data
238
256
# Reading the data in file sequence instead of seeking and fetching it later is preferred,
239
257
# 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 )
241
259
self .outOfOrderSize += inLen
242
260
else : # If no space in cache, seek forward
243
261
self .inF .seek (inLen , os .SEEK_CUR )
0 commit comments