#!/usr/bin/env python3 import itertools as it import math as m import struct def crc32c(data, crc=0): crc ^= 0xffffffff for b in data: crc ^= b for j in range(8): crc = (crc >> 1) ^ ((crc & 1) * 0x82f63b78) return 0xffffffff ^ crc def fromleb128(data): word = 0 for i, b in enumerate(data): word |= ((b & 0x7f) << 7*i) word &= 0xffffffff if not b & 0x80: return word, i+1 return word, len(data) def fromtag(data): tag, delta1 = fromleb128(data) size, delta2 = fromleb128(data[delta1:]) return tag & 1, tag >> 1, size, delta1+delta2 def popc(x): return bin(x).count('1') def xxd(data, width=16, crc=False): for i in range(0, len(data), width): yield '%-*s %-*s' % ( 3*width, ' '.join('%02x' % b for b in data[i:i+width]), width, ''.join( b if b >= ' ' and b <= '~' else '.' for b in map(chr, data[i:i+width]))) def tagrepr(tag, size, off=None): type1 = tag & 0x7f type2 = (tag >> 7) & 0xff id = (tag >> 15) & 0xffff if type1 & 1: return 'alt %s %s x%x %s' % ( 'r' if type1 & 4 else 'b', 'gt' if type1 & 2 else 'lt', tag >> 3, 'x%x' % (0xffffffff & (off-size)) if off is not None else '-%d' % off) elif type1 == 0x40: return 'create x%02x id%d %d' % (type2, id, size) elif type1 == 0x48: return 'delete x%02x id%d %d' % (type2, id, size) elif type1 == 0x50: return 'struct x%02x id%d %d' % (type2, id, size) elif type1 == 0x60: return 'uattr x%02x id%d %d' % (type2, id, size) elif type1 == 0x08: if type2 == 0: return 'tail %d' % size else: return 'tail x%02x %d' % (type2, size) elif type1 == 0x10: return 'gstate x%02x %d' % (type2, size) elif type1 == 0x02 or type1 == 0x0a: if type2 == 0: return 'crc%x %d' % (type1 >> 3, size) else: return 'crc%x x%02x %d' % (type1 >> 3, type2, size) elif type1 == 0x12: if type2 == 0: return 'fcrc %d' % (size) else: return 'fcrc x%02x %d' % (type2, size) else: return 'x%02x x%02x id%d %d' % (type1, type2, id, size) def main(disk, block_size, block1, block2=None, **args): # read each block blocks = [block for block in [block1, block2] if block is not None] with open(disk, 'rb') as f: datas = [] for block in blocks: f.seek(block * block_size) datas.append(f.read(block_size)) # first figure out which block as the most recent revision def fetch(data): rev, = struct.unpack('