#!/usr/bin/env python3 import struct import sys import json import io import itertools as it from readmdir import Tag, MetadataPair def popc(x): return bin(x).count('1') def ctz(x): return len(bin(x)) - len(bin(x).rstrip('0')) def dumptags(args, mdir, f): if args.all: tags = mdir.all_ elif args.log: tags = mdir.log else: tags = mdir.tags for k, tag in enumerate(tags): f.write("tag %08x %s" % (tag, tag.typerepr())) if tag.id != 0x3ff: f.write(" id %d" % tag.id) if tag.size != 0x3ff: f.write(" size %d" % tag.size) if tag.is_('name'): f.write(" name %s" % json.dumps(tag.data.decode('utf8'))) if tag.is_('dirstruct'): f.write(" dir {%#x, %#x}" % struct.unpack( '= ' ' and c <= '~' else '.' for c in map(chr, tag.data[i:i+16])))) def dumpentries(args, mdir, f): for k, id_ in enumerate(mdir.ids): name = mdir[Tag('name', id_, 0)] struct_ = mdir[Tag('struct', id_, 0)] f.write("id %d %s %s" % ( name.id, name.typerepr(), json.dumps(name.data.decode('utf8')))) if struct_.is_('dirstruct'): f.write(" dir {%#x, %#x}" % struct.unpack( '= ' ' and c <= '~' else '.' for c in map(chr, struct_.data[i:i+16])))) elif args.data and struct_.is_('ctzstruct'): block, size = struct.unpack( '= 0: f2.seek(block * args.block_size) dat = f2.read(args.block_size) data.append(dat[4*(ctz(i)+1) if i != 0 else 0:]) block, = struct.unpack('= ' ' and c <= '~' else '.' for c in map(chr, data[i:i+16])))) for tag in mdir.tags: if tag.id==id_ and tag.is_('userattr'): f.write("id %d %s size %d\n" % ( id_, tag.typerepr(), tag.size)) if args.data: for i in range(0, len(tag.data), 16): f.write(" %-47s %-16s\n" % ( ' '.join('%02x' % c for c in tag.data[i:i+16]), ''.join(c if c >= ' ' and c <= '~' else '.' for c in map(chr, tag.data[i:i+16])))) def main(args): with open(args.disk, 'rb') as f: dirs = [] superblock = None gstate = b'' mdirs = [] tail = (args.block1, args.block2) hard = False while True: # 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 # 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('