Modified readmdir/readtree to make reading non-truncated data easier

Added indention so there was a more clear separation between the tag
description and tag data.

Also took the best parts of readmdir.py and added it to readtree.py.
Initially I was thinking it was best for these to have completely
independent data representations, since you could always call readtree
to get more info, but this becomes tedius when needed to look at
low-level tag info across multiple directories on the filesystem.
This commit is contained in:
Christopher Haster
2020-01-30 16:05:42 -06:00
parent f9c2fd93f2
commit 6a550844f4
2 changed files with 33 additions and 65 deletions

View File

@@ -2,6 +2,7 @@
import struct import struct
import binascii import binascii
import sys
import itertools as it import itertools as it
TAG_TYPES = { TAG_TYPES = {
@@ -271,37 +272,39 @@ class MetadataPair:
raise KeyError(gmask, gtag) raise KeyError(gmask, gtag)
def _dump_tags(self, tags, truncate=True): def _dump_tags(self, tags, f=sys.stdout, truncate=True):
sys.stdout.write("%-8s %-8s %-13s %4s %4s %s\n" % ( f.write("%-8s %-8s %-13s %4s %4s" % (
'off', 'tag', 'type', 'id', 'len', 'off', 'tag', 'type', 'id', 'len'))
'data (truncated)' if truncate else 12*' '+'data')) if truncate:
f.write(' data (truncated)')
f.write('\n')
for tag in tags: for tag in tags:
sys.stdout.write("%08x: %08x %-13s %4s %4s" % ( f.write("%08x: %08x %-13s %4s %4s" % (
tag.off, tag, tag.off, tag,
tag.typerepr(), tag.idrepr(), tag.sizerepr())) tag.typerepr(), tag.idrepr(), tag.sizerepr()))
if truncate: if truncate:
sys.stdout.write(" %-23s %-8s\n" % ( f.write(" %-23s %-8s\n" % (
' '.join('%02x' % c for c in tag.data[:8]), ' '.join('%02x' % c for c in tag.data[:8]),
''.join(c if c >= ' ' and c <= '~' else '.' ''.join(c if c >= ' ' and c <= '~' else '.'
for c in map(chr, tag.data[:8])))) for c in map(chr, tag.data[:8]))))
else: else:
sys.stdout.write("\n") f.write("\n")
for i in range(0, len(tag.data), 16): for i in range(0, len(tag.data), 16):
sys.stdout.write("%08x: %-47s %-16s\n" % ( f.write(" %08x: %-47s %-16s\n" % (
tag.off+i, tag.off+i,
' '.join('%02x' % c for c in tag.data[i:i+16]), ' '.join('%02x' % c for c in tag.data[i:i+16]),
''.join(c if c >= ' ' and c <= '~' else '.' ''.join(c if c >= ' ' and c <= '~' else '.'
for c in map(chr, tag.data[i:i+16])))) for c in map(chr, tag.data[i:i+16]))))
def dump_tags(self, truncate=True): def dump_tags(self, f=sys.stdout, truncate=True):
self._dump_tags(self.tags, truncate=truncate) self._dump_tags(self.tags, f=f, truncate=truncate)
def dump_log(self, truncate=True): def dump_log(self, f=sys.stdout, truncate=True):
self._dump_tags(self.log, truncate=truncate) self._dump_tags(self.log, f=f, truncate=truncate)
def dump_all(self, truncate=True): def dump_all(self, f=sys.stdout, truncate=True):
self._dump_tags(self.all_, truncate=truncate) self._dump_tags(self.all_, f=f, truncate=truncate)
def main(args): def main(args):
blocks = [] blocks = []
@@ -337,10 +340,10 @@ if __name__ == "__main__":
help="First block address for finding the metadata pair.") help="First block address for finding the metadata pair.")
parser.add_argument('block2', nargs='?', type=lambda x: int(x, 0), parser.add_argument('block2', nargs='?', type=lambda x: int(x, 0),
help="Second block address for finding the metadata pair.") help="Second block address for finding the metadata pair.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all tags in log, included tags in corrupted commits.")
parser.add_argument('-l', '--log', action='store_true', parser.add_argument('-l', '--log', action='store_true',
help="Show tags in log.") 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('-T', '--no-truncate', action='store_true', parser.add_argument('-T', '--no-truncate', action='store_true',
help="Don't truncate large amounts of data in tags.") help="Don't truncate large amounts of data.")
sys.exit(main(parser.parse_args())) sys.exit(main(parser.parse_args()))

View File

@@ -13,45 +13,6 @@ def popc(x):
def ctz(x): def ctz(x):
return len(bin(x)) - len(bin(x).rstrip('0')) 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(
'<II', tag.data[:8].ljust(8, b'\xff')))
if tag.is_('ctzstruct'):
f.write(" ctz {%#x} size %d" % struct.unpack(
'<II', tag.data[:8].ljust(8, b'\xff')))
if tag.is_('inlinestruct'):
f.write(" inline size %d" % tag.size)
if tag.is_('gstate'):
f.write(" 0x%s" % ''.join('%02x' % c for c in tag.data))
if tag.is_('tail'):
f.write(" tail {%#x, %#x}" % struct.unpack(
'<II', tag.data[:8].ljust(8, b'\xff')))
f.write("\n")
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 dumpentries(args, mdir, f): def dumpentries(args, mdir, f):
for k, id_ in enumerate(mdir.ids): for k, id_ in enumerate(mdir.ids):
name = mdir[Tag('name', id_, 0)] name = mdir[Tag('name', id_, 0)]
@@ -72,8 +33,8 @@ def dumpentries(args, mdir, f):
if args.data and struct_.is_('inlinestruct'): if args.data and struct_.is_('inlinestruct'):
for i in range(0, len(struct_.data), 16): for i in range(0, len(struct_.data), 16):
f.write(" %-47s %-16s\n" % ( f.write(" %08x: %-47s %-16s\n" % (
' '.join('%02x' % c for c in struct_.data[i:i+16]), i, ' '.join('%02x' % c for c in struct_.data[i:i+16]),
''.join(c if c >= ' ' and c <= '~' else '.' ''.join(c if c >= ' ' and c <= '~' else '.'
for c in map(chr, struct_.data[i:i+16])))) for c in map(chr, struct_.data[i:i+16]))))
elif args.data and struct_.is_('ctzstruct'): elif args.data and struct_.is_('ctzstruct'):
@@ -95,8 +56,8 @@ def dumpentries(args, mdir, f):
it.chain.from_iterable(reversed(data)), size)) it.chain.from_iterable(reversed(data)), size))
for i in range(0, min(len(data), 256) for i in range(0, min(len(data), 256)
if not args.no_truncate else len(data), 16): if not args.no_truncate else len(data), 16):
f.write(" %-47s %-16s\n" % ( f.write(" %08x: %-47s %-16s\n" % (
' '.join('%02x' % c for c in data[i:i+16]), i, ' '.join('%02x' % c for c in data[i:i+16]),
''.join(c if c >= ' ' and c <= '~' else '.' ''.join(c if c >= ' ' and c <= '~' else '.'
for c in map(chr, data[i:i+16])))) for c in map(chr, data[i:i+16]))))
@@ -239,8 +200,12 @@ def main(args):
' (corrupted)' if not mdir else '')) ' (corrupted)' if not mdir else ''))
f = io.StringIO() f = io.StringIO()
if args.tags or args.all or args.log: if args.tags:
dumptags(args, mdir, f) 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: else:
dumpentries(args, mdir, f) dumpentries(args, mdir, f)
@@ -285,12 +250,12 @@ if __name__ == "__main__":
help="Show contents of metadata-pairs/directories.") help="Show contents of metadata-pairs/directories.")
parser.add_argument('-t', '--tags', action='store_true', parser.add_argument('-t', '--tags', action='store_true',
help="Show metadata tags instead of reconstructing entries.") help="Show metadata tags instead of reconstructing entries.")
parser.add_argument('-a', '--all', action='store_true',
help="Show all tags in log, included tags in corrupted commits.")
parser.add_argument('-l', '--log', action='store_true', parser.add_argument('-l', '--log', action='store_true',
help="Show tags in log.") 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', parser.add_argument('-d', '--data', action='store_true',
help="Also show the raw contents of files/attrs/tags.") help="Also show the raw contents of files/attrs/tags.")
parser.add_argument('-T', '--no-truncate', action='store_true', parser.add_argument('-T', '--no-truncate', action='store_true',
help="Don't truncate large amounts of data in files.") help="Don't truncate large amounts of data.")
sys.exit(main(parser.parse_args())) sys.exit(main(parser.parse_args()))