#!/usr/bin/env python3 import struct import sys import json import io import itertools as it from readmdir import Tag, MetadataPair def main(args): superblock = None gstate = b'\0\0\0\0\0\0\0\0\0\0\0\0' dirs = [] mdirs = [] corrupted = [] cycle = False with open(args.disk, 'rb') as f: tail = (args.block1, args.block2) hard = False while True: for m in it.chain((m for d in dirs for m in d), mdirs): if set(m.blocks) == set(tail): # cycle detected cycle = m.blocks if cycle: break # load mdir data = [] blocks = {} for block in tail: f.seek(block * args.block_size) data.append(f.read(args.block_size) .ljust(args.block_size, b'\xff')) blocks[id(data[-1])] = block mdir = MetadataPair(data) mdir.blocks = tuple(blocks[id(p.data)] for p in mdir.pair) # fetch some key metadata as a we scan try: mdir.tail = mdir[Tag('tail', 0, 0)] if mdir.tail.size != 8 or mdir.tail.data == 8*b'\xff': mdir.tail = None except KeyError: mdir.tail = None # have superblock? try: nsuperblock = mdir[ Tag(0x7ff, 0x3ff, 0), Tag('superblock', 0, 0)] superblock = nsuperblock, mdir[Tag('inlinestruct', 0, 0)] except KeyError: pass # have gstate? try: ngstate = mdir[Tag('movestate', 0, 0)] gstate = bytes((a or 0) ^ (b or 0) for a,b in it.zip_longest(gstate, ngstate.data)) except KeyError: pass # corrupted? if not mdir: corrupted.append(mdir) # add to directories mdirs.append(mdir) if mdir.tail is None or not mdir.tail.is_('hardtail'): dirs.append(mdirs) mdirs = [] if mdir.tail is None: break tail = struct.unpack('=%d" % max(tag.size, 1)) if tag.type: print(" move dir {%#x, %#x} id %d" % ( blocks[0], blocks[1], tag.id)) # print mdir info for i, dir in enumerate(dirs): print("dir %s" % (json.dumps(dir[0].path) if hasattr(dir[0], 'path') else '(orphan)')) for j, mdir in enumerate(dir): print("mdir {%#x, %#x} rev %d (was %d)%s%s" % ( mdir.blocks[0], mdir.blocks[1], mdir.rev, mdir.pair[1].rev, ' (corrupted!)' if not mdir else '', ' -> {%#x, %#x}' % struct.unpack('