diff --git a/scripts/explode_asserts.py b/scripts/explode_asserts.py index c0534cb..8a8e5b1 100755 --- a/scripts/explode_asserts.py +++ b/scripts/explode_asserts.py @@ -166,8 +166,8 @@ def mkassert(type, comp, lh, rh, size=None): 'type': type.lower(), 'TYPE': type.upper(), 'comp': comp.lower(), 'COMP': comp.upper(), 'prefix': PREFIX.lower(), 'PREFIX': PREFIX.upper(), - 'lh': lh.strip(), - 'rh': rh.strip(), + 'lh': lh.strip(' '), + 'rh': rh.strip(' '), 'size': size, } if size: diff --git a/scripts/readmdir.py b/scripts/readmdir.py index ef634a9..75f8b9a 100755 --- a/scripts/readmdir.py +++ b/scripts/readmdir.py @@ -318,6 +318,14 @@ def main(args): # find most recent pair mdir = MetadataPair(blocks) + print("mdir {%s} rev %d%s%s" % ( + ', '.join('%#x' % b + for b in [args.block1, args.block2] + if b is not None), + mdir.rev, + ' (was %s)' % ', '.join('%d' % m.rev for m in mdir.pair[1:]) + if len(mdir.pair) > 1 else '', + ' (corrupted)' if not mdir else '')) if args.all: mdir.dump_all(truncate=not args.no_truncate) elif args.log: diff --git a/scripts/readtree.py b/scripts/readtree.py index ea8cb5f..3965a36 100755 --- a/scripts/readtree.py +++ b/scripts/readtree.py @@ -18,26 +18,22 @@ def dumpentries(args, mdir, f): name = mdir[Tag('name', id_, 0)] struct_ = mdir[Tag('struct', id_, 0)] - f.write("id %d %s %s" % ( + desc = "id %d %s %s" % ( id_, name.typerepr(), - json.dumps(name.data.decode('utf8')))) + 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'): + data = None + if struct_.is_('inlinestruct'): + data = struct_.data + elif struct_.is_('ctzstruct'): block, size = struct.unpack( '= ' ' and c <= '~' else '.' + for c in map(chr, data[:8]))) + if not args.no_truncate and len(desc) < 45 + and data is not None else "")) + + if name.is_('superblock') and struct_.is_('inlinestruct'): + f.write( + " block_size %d\n" + " block_count %d\n" + " name_max %d\n" + " file_max %d\n" + " attr_max %d\n" % struct.unpack( + '= ' ' and c <= '~' else '.' + for c in map(chr, tag.data[:8]))) + if not args.no_truncate and len(desc) < 43 else "")) + + if args.no_truncate: + for i in range(0, len(tag.data), 16): + f.write(" %08x: %-47s %-16s\n" % ( + i, ' '.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])))) + + if args.no_truncate and data is not None: + for i in range(0, len(data), 16): f.write(" %08x: %-47s %-16s\n" % ( i, ' '.join('%02x' % c for c in data[i:i+16]), ''.join(c if c >= ' ' 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 = [] @@ -161,61 +179,51 @@ def main(args): dir[0].path = path.replace('//', '/') # dump tree - if not args.superblock and not args.gstate and not args.mdirs: - args.superblock = True - args.gstate = True - args.mdirs = True + version = ('?', '?') + if superblock: + version = tuple(reversed( + struct.unpack('=%d" % max(tag.size, 1)) if tag.type: print(" move dir {%#x, %#x} id %d" % ( blocks[0], blocks[1], tag.id)) - if args.mdirs: - for i, dir in enumerate(dirs): - print("dir %s" % (json.dumps(dir[0].path) - if hasattr(dir[0], 'path') else '(orphan)')) + 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%s" % ( - mdir.blocks[0], mdir.blocks[1], mdir.rev, - ' (corrupted)' if not mdir else '')) + for j, mdir in enumerate(dir): + print("mdir {%#x, %#x} rev %d%s" % ( + mdir.blocks[0], mdir.blocks[1], mdir.rev, + ' (corrupted)' if not mdir else '')) - f = io.StringIO() - if args.tags: - mdir.dump_tags(f, truncate=not args.no_truncate) - elif args.log: - mdir.dump_log(f, truncate=not args.no_truncate) - elif args.all: - mdir.dump_all(f, truncate=not args.no_truncate) - else: - dumpentries(args, mdir, f) + f = io.StringIO() + if args.tags: + mdir.dump_tags(f, truncate=not args.no_truncate) + elif args.log: + mdir.dump_log(f, truncate=not args.no_truncate) + elif args.all: + mdir.dump_all(f, truncate=not args.no_truncate) + else: + dumpentries(args, mdir, f) - lines = list(filter(None, f.getvalue().split('\n'))) - for k, line in enumerate(lines): - print("%s %s" % ( - ' ' if j == len(dir)-1 else - 'v' if k == len(lines)-1 else - '|', - line)) + lines = list(filter(None, f.getvalue().split('\n'))) + for k, line in enumerate(lines): + print("%s %s" % ( + ' ' if i == len(dirs)-1 and j == len(dir)-1 else + 'v' if k == len(lines)-1 else + '.' if j == len(dir)-1 else + '|', + line)) if cycle: print("*** cycle detected! -> {%#x, %#x} ***" % (cycle[0], cycle[1])) @@ -242,20 +250,12 @@ if __name__ == "__main__": parser.add_argument('block2', nargs='?', default=1, type=lambda x: int(x, 0), help="Optional second block address for finding the root.") - parser.add_argument('-s', '--superblock', action='store_true', - help="Show contents of the superblock.") - parser.add_argument('-g', '--gstate', action='store_true', - help="Show contents of global-state.") - parser.add_argument('-m', '--mdirs', action='store_true', - help="Show contents of metadata-pairs/directories.") parser.add_argument('-t', '--tags', action='store_true', help="Show metadata tags instead of reconstructing entries.") parser.add_argument('-l', '--log', action='store_true', help="Show tags in log.") parser.add_argument('-a', '--all', action='store_true', help="Show all tags in log, included tags in corrupted commits.") - parser.add_argument('-d', '--data', action='store_true', - help="Also show the raw contents of files/attrs/tags.") parser.add_argument('-T', '--no-truncate', action='store_true', - help="Don't truncate large amounts of data.") + help="Show the full contents of files/attrs/tags.") sys.exit(main(parser.parse_args()))