Updated dbg scripts to support shrub trees

- Added shrub tags to tagrepr
- Modified dbgrbyd.py to use last non-shrub trunk by default
- Tweaked dbgrbyd's log mode to find maximum seen weight for id padding
This commit is contained in:
Christopher Haster
2023-09-21 23:41:36 -05:00
parent dc8bc447e6
commit 3fb4350ce7
5 changed files with 451 additions and 363 deletions
+1 -1
View File
@@ -718,7 +718,7 @@ static inline bool lfsr_tag_clearshrub(lfsr_tag_t tag) {
} }
static inline bool lfsr_tag_istrunk(lfsr_tag_t tag) { static inline bool lfsr_tag_istrunk(lfsr_tag_t tag) {
return (tag & 0x6000) != 0x2000; return (tag & 0xe000) != 0x2000;
} }
static inline bool lfsr_tag_isinternal(lfsr_tag_t tag) { static inline bool lfsr_tag_isinternal(lfsr_tag_t tag) {
+93 -78
View File
@@ -39,10 +39,13 @@ TAG_MTREE = 0x0314
TAG_MROOT = 0x0318 TAG_MROOT = 0x0318
TAG_DID = 0x031c TAG_DID = 0x031c
TAG_UATTR = 0x0400 TAG_UATTR = 0x0400
TAG_SATTR = 0x0500 TAG_SATTR = 0x0600
TAG_ALT = 0x4000 TAG_SHRUB = 0x1000
TAG_CKSUM = 0x2000 TAG_CKSUM = 0x2000
TAG_ECKSUM = 0x2100 TAG_ECKSUM = 0x2100
TAG_ALT = 0x4000
TAG_GT = 0x2000
TAG_R = 0x1000
# parse some rbyd addr encodings # parse some rbyd addr encodings
@@ -130,78 +133,86 @@ def xxd(data, width=16):
for b in map(chr, data[i:i+width]))) for b in map(chr, data[i:i+width])))
def tagrepr(tag, w, size, off=None): def tagrepr(tag, w, size, off=None):
if tag == TAG_NULL: if (tag & 0xefff) == TAG_NULL:
return 'null%s%s' % ( return '%snull%s%s' % (
'shrub' if tag & TAG_SHRUB else '',
' w%d' % w if w else '', ' w%d' % w if w else '',
' %d' % size if size else '') ' %d' % size if size else '')
elif (tag & 0xff00) == TAG_CONFIG: elif (tag & 0xef00) == TAG_CONFIG:
return '%s%s %d' % ( return '%s%s%s %d' % (
'magic' if tag == TAG_MAGIC 'shrub' if tag & TAG_SHRUB else '',
else 'version' if tag == TAG_VERSION 'magic' if (tag & 0xfff) == TAG_MAGIC
else 'flags' if tag == TAG_FLAGS else 'version' if (tag & 0xfff) == TAG_VERSION
else 'cksumtype' if tag == TAG_CKSUMTYPE else 'flags' if (tag & 0xfff) == TAG_FLAGS
else 'redundtype' if tag == TAG_REDUNDTYPE else 'cksumtype' if (tag & 0xfff) == TAG_CKSUMTYPE
else 'blocklimit' if tag == TAG_BLOCKLIMIT else 'redundtype' if (tag & 0xfff) == TAG_REDUNDTYPE
else 'disklimit' if tag == TAG_DISKLIMIT else 'blocklimit' if (tag & 0xfff) == TAG_BLOCKLIMIT
else 'mleaflimit' if tag == TAG_MLEAFLIMIT else 'disklimit' if (tag & 0xfff) == TAG_DISKLIMIT
else 'sizelimit' if tag == TAG_SIZELIMIT else 'mleaflimit' if (tag & 0xfff) == TAG_MLEAFLIMIT
else 'namelimit' if tag == TAG_NAMELIMIT else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
else 'utaglimit' if tag == TAG_UTAGLIMIT else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
else 'uattrlimit' if tag == TAG_UATTRLIMIT else 'utaglimit' if (tag & 0xfff) == TAG_UTAGLIMIT
else 'uattrlimit' if (tag & 0xfff) == TAG_UATTRLIMIT
else 'config 0x%02x' % (tag & 0xff), else 'config 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_GSTATE: elif (tag & 0xef00) == TAG_GSTATE:
return '%s%s %d' % ( return '%s%s%s %d' % (
'grm' if tag == TAG_GRM 'shrub' if tag & TAG_SHRUB else '',
'grm' if (tag & 0xfff) == TAG_GRM
else 'gstate 0x%02x' % (tag & 0xff), else 'gstate 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_NAME: elif (tag & 0xef00) == TAG_NAME:
return '%s%s %d' % ( return '%s%s%s %d' % (
'branch' if tag == TAG_BRANCH 'shrub' if tag & TAG_SHRUB else '',
else 'bookmark' if tag == TAG_BOOKMARK 'branch' if (tag & 0xfff) == TAG_BRANCH
else 'reg' if tag == TAG_REG else 'bookmark' if (tag & 0xfff) == TAG_BOOKMARK
else 'dir' if tag == TAG_DIR else 'reg' if (tag & 0xfff) == TAG_REG
else 'dir' if (tag & 0xfff) == TAG_DIR
else 'name 0x%02x' % (tag & 0xff), else 'name 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_STRUCT: elif (tag & 0xef00) == TAG_STRUCT:
return '%s%s %d' % ( return '%s%s%s %d' % (
'inlined' if tag == TAG_INLINED 'shrub' if tag & TAG_SHRUB else '',
else 'trunk' if tag == TAG_TRUNK 'inlined' if (tag & 0xfff) == TAG_INLINED
else 'block' if tag == TAG_BLOCK else 'trunk' if (tag & 0xfff) == TAG_TRUNK
else 'btree' if tag == TAG_BTREE else 'block' if (tag & 0xfff) == TAG_BLOCK
else 'mdir' if tag == TAG_MDIR else 'btree' if (tag & 0xfff) == TAG_BTREE
else 'mtree' if tag == TAG_MTREE else 'mdir' if (tag & 0xfff) == TAG_MDIR
else 'mroot' if tag == TAG_MROOT else 'mtree' if (tag & 0xfff) == TAG_MTREE
else 'did' if tag == TAG_DID else 'mroot' if (tag & 0xfff) == TAG_MROOT
else 'did' if (tag & 0xfff) == TAG_DID
else 'struct 0x%02x' % (tag & 0xff), else 'struct 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_UATTR: elif (tag & 0xef00) == TAG_UATTR:
return 'uattr 0x%02x%s %d' % ( return '%suattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_SATTR: elif (tag & 0xef00) == TAG_SATTR:
return 'sattr 0x%02x%s %d' % ( return '%ssattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_CKSUM: elif (tag & 0xff00) == TAG_CKSUM:
return 'cksum%x%s %d' % ( return 'cksum 0x%02x%s %d' % (
1 if tag & 0x1 else 0, tag & 0xff,
' 0x%x' % w if w > 0 else '', ' w%d' % w if w > 0 else '',
size) size)
elif tag == TAG_ECKSUM: elif (tag & 0xff00) == TAG_ECKSUM:
return 'ecksum%s %d' % ( return 'ecksum%s%s %d' % (
' 0x%x' % w if w > 0 else '', ' 0x%02x' % (tag & 0xff) if tag & 0xff else '',
' w%d' % w if w > 0 else '',
size) size)
elif tag & 0x4000: elif tag & TAG_ALT:
return 'alt%s%s 0x%x w%d %s' % ( return 'alt%s%s 0x%x w%d %s' % (
'r' if tag & 0x1000 else 'b', 'r' if tag & TAG_R else 'b',
'gt' if tag & 0x2000 else 'le', 'gt' if tag & TAG_GT else 'le',
tag & 0x0fff, tag & 0x0fff,
w, w,
'0x%x' % (0xffffffff & (off-size)) '0x%x' % (0xffffffff & (off-size))
@@ -216,11 +227,11 @@ TBranch = co.namedtuple('TBranch', 'a, b, d, c')
# our core rbyd type # our core rbyd type
class Rbyd: class Rbyd:
def __init__(self, block, data, rev, off, trunk, weight): def __init__(self, block, data, rev, eoff, trunk, weight):
self.block = block self.block = block
self.data = data self.data = data
self.rev = rev self.rev = rev
self.off = off self.eoff = eoff
self.trunk = trunk self.trunk = trunk
self.weight = weight self.weight = weight
self.redund_blocks = [] self.redund_blocks = []
@@ -273,26 +284,27 @@ class Rbyd:
rev = fromle32(data[0:4]) rev = fromle32(data[0:4])
cksum = 0 cksum = 0
cksum_ = crc32c(data[0:4]) cksum_ = crc32c(data[0:4])
off = 0 eoff = 0
j_ = 4 j_ = 4
trunk_ = 0 trunk_ = 0
trunk__ = 0 trunk__ = 0
trunk___ = 0
weight = 0 weight = 0
weight_ = 0 weight_ = 0
weight__ = 0 weight__ = 0
wastrunk = False wastrunk = False
trunkoff = None trunkeoff = None
while j_ < len(data) and (not trunk or off <= trunk): while j_ < len(data) and (not trunk or eoff <= trunk):
v, tag, w, size, d = fromtag(data[j_:]) v, tag, w, size, d = fromtag(data[j_:])
if v != (popc(cksum_) & 1): if v != (popc(cksum_) & 1):
break break
cksum_ = crc32c(data[j_:j_+d], cksum_) cksum_ = crc32c(data[j_:j_+d], cksum_)
j_ += d j_ += d
if not tag & 0x4000 and j_ + size > len(data): if not tag & TAG_ALT and j_ + size > len(data):
break break
# take care of cksums # take care of cksums
if not tag & 0x4000: if not tag & TAG_ALT:
if (tag & 0xff00) != TAG_CKSUM: if (tag & 0xff00) != TAG_CKSUM:
cksum_ = crc32c(data[j_:j_+size], cksum_) cksum_ = crc32c(data[j_:j_+size], cksum_)
# found a cksum? # found a cksum?
@@ -301,36 +313,39 @@ class Rbyd:
if cksum_ != cksum__: if cksum_ != cksum__:
break break
# commit what we have # commit what we have
off = trunkoff if trunkoff else j_ + size eoff = trunkeoff if trunkeoff else j_ + size
cksum = cksum_ cksum = cksum_
trunk_ = trunk__ trunk_ = trunk__
weight = weight_ weight = weight_
# evaluate trunks # evaluate trunks
if (tag & 0xe000) != 0x2000 and ( if (tag & 0xe000) != TAG_CKSUM and (
not trunk or trunk >= j_-d or wastrunk): not trunk or trunk >= j_-d or wastrunk):
# new trunk? # new trunk?
if not wastrunk: if not wastrunk:
wastrunk = True wastrunk = True
trunk__ = j_-d trunk___ = j_-d
weight__ = 0 weight__ = 0
# keep track of weight # keep track of weight
weight__ += w weight__ += w
# end of trunk? # end of trunk?
if not tag & 0x4000: if not tag & TAG_ALT:
wastrunk = False wastrunk = False
# update weight # update trunk/weight unless we found a shrub or an
# explicit trunk (which may be a shrub) is requested
if not tag & TAG_SHRUB or trunk:
trunk__ = trunk___
weight_ = weight__ weight_ = weight__
# keep track of off for best matching trunk # keep track of eoff for best matching trunk
if trunk and j_ + size > trunk: if trunk and j_ + size > trunk:
trunkoff = j_ + size trunkeoff = j_ + size
if not tag & 0x4000: if not tag & TAG_ALT:
j_ += size j_ += size
return cls(block, data, rev, off, trunk_, weight) return cls(block, data, rev, eoff, trunk_, weight)
def lookup(self, rid, tag): def lookup(self, rid, tag):
if not self: if not self:
@@ -346,20 +361,20 @@ class Rbyd:
_, alt, weight_, jump, d = fromtag(self.data[j:]) _, alt, weight_, jump, d = fromtag(self.data[j:])
# found an alt? # found an alt?
if alt & 0x4000: if alt & TAG_ALT:
# follow? # follow?
if ((rid, tag & 0xfff) > (upper-weight_-1, alt & 0xfff) if ((rid, tag & 0xfff) > (upper-weight_-1, alt & 0xfff)
if alt & 0x2000 if alt & TAG_GT
else ((rid, tag & 0xfff) else ((rid, tag & 0xfff)
<= (lower+weight_, alt & 0xfff))): <= (lower+weight_, alt & 0xfff))):
lower += upper-lower-1-weight_ if alt & 0x2000 else 0 lower += upper-lower-1-weight_ if alt & TAG_GT else 0
upper -= upper-lower-1-weight_ if not alt & 0x2000 else 0 upper -= upper-lower-1-weight_ if not alt & TAG_GT else 0
j = j - jump j = j - jump
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(self.data[j+jump+d:]) _, nalt, _, _, _ = fromtag(self.data[j+jump+d:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j+jump, j, True, 'y')) path.append((j+jump, j, True, 'y'))
else: else:
path.append((j+jump, j, True, 'r')) path.append((j+jump, j, True, 'r'))
@@ -368,14 +383,14 @@ class Rbyd:
# stay on path # stay on path
else: else:
lower += weight_ if not alt & 0x2000 else 0 lower += weight_ if not alt & TAG_GT else 0
upper -= weight_ if alt & 0x2000 else 0 upper -= weight_ if alt & TAG_GT else 0
j = j + d j = j + d
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(self.data[j:]) _, nalt, _, _, _ = fromtag(self.data[j:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j-d, j, False, 'y')) path.append((j-d, j, False, 'y'))
else: else:
path.append((j-d, j, False, 'r')) path.append((j-d, j, False, 'r'))
+93 -78
View File
@@ -40,10 +40,13 @@ TAG_MTREE = 0x0314
TAG_MROOT = 0x0318 TAG_MROOT = 0x0318
TAG_DID = 0x031c TAG_DID = 0x031c
TAG_UATTR = 0x0400 TAG_UATTR = 0x0400
TAG_SATTR = 0x0500 TAG_SATTR = 0x0600
TAG_ALT = 0x4000 TAG_SHRUB = 0x1000
TAG_CKSUM = 0x2000 TAG_CKSUM = 0x2000
TAG_ECKSUM = 0x2100 TAG_ECKSUM = 0x2100
TAG_ALT = 0x4000
TAG_GT = 0x2000
TAG_R = 0x1000
# parse some rbyd addr encodings # parse some rbyd addr encodings
@@ -140,78 +143,86 @@ def xxd(data, width=16):
for b in map(chr, data[i:i+width]))) for b in map(chr, data[i:i+width])))
def tagrepr(tag, w, size, off=None): def tagrepr(tag, w, size, off=None):
if tag == TAG_NULL: if (tag & 0xefff) == TAG_NULL:
return 'null%s%s' % ( return '%snull%s%s' % (
'shrub' if tag & TAG_SHRUB else '',
' w%d' % w if w else '', ' w%d' % w if w else '',
' %d' % size if size else '') ' %d' % size if size else '')
elif (tag & 0xff00) == TAG_CONFIG: elif (tag & 0xef00) == TAG_CONFIG:
return '%s%s %d' % ( return '%s%s%s %d' % (
'magic' if tag == TAG_MAGIC 'shrub' if tag & TAG_SHRUB else '',
else 'version' if tag == TAG_VERSION 'magic' if (tag & 0xfff) == TAG_MAGIC
else 'flags' if tag == TAG_FLAGS else 'version' if (tag & 0xfff) == TAG_VERSION
else 'cksumtype' if tag == TAG_CKSUMTYPE else 'flags' if (tag & 0xfff) == TAG_FLAGS
else 'redundtype' if tag == TAG_REDUNDTYPE else 'cksumtype' if (tag & 0xfff) == TAG_CKSUMTYPE
else 'blocklimit' if tag == TAG_BLOCKLIMIT else 'redundtype' if (tag & 0xfff) == TAG_REDUNDTYPE
else 'disklimit' if tag == TAG_DISKLIMIT else 'blocklimit' if (tag & 0xfff) == TAG_BLOCKLIMIT
else 'mleaflimit' if tag == TAG_MLEAFLIMIT else 'disklimit' if (tag & 0xfff) == TAG_DISKLIMIT
else 'sizelimit' if tag == TAG_SIZELIMIT else 'mleaflimit' if (tag & 0xfff) == TAG_MLEAFLIMIT
else 'namelimit' if tag == TAG_NAMELIMIT else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
else 'utaglimit' if tag == TAG_UTAGLIMIT else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
else 'uattrlimit' if tag == TAG_UATTRLIMIT else 'utaglimit' if (tag & 0xfff) == TAG_UTAGLIMIT
else 'uattrlimit' if (tag & 0xfff) == TAG_UATTRLIMIT
else 'config 0x%02x' % (tag & 0xff), else 'config 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_GSTATE: elif (tag & 0xef00) == TAG_GSTATE:
return '%s%s %d' % ( return '%s%s%s %d' % (
'grm' if tag == TAG_GRM 'shrub' if tag & TAG_SHRUB else '',
'grm' if (tag & 0xfff) == TAG_GRM
else 'gstate 0x%02x' % (tag & 0xff), else 'gstate 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_NAME: elif (tag & 0xef00) == TAG_NAME:
return '%s%s %d' % ( return '%s%s%s %d' % (
'branch' if tag == TAG_BRANCH 'shrub' if tag & TAG_SHRUB else '',
else 'bookmark' if tag == TAG_BOOKMARK 'branch' if (tag & 0xfff) == TAG_BRANCH
else 'reg' if tag == TAG_REG else 'bookmark' if (tag & 0xfff) == TAG_BOOKMARK
else 'dir' if tag == TAG_DIR else 'reg' if (tag & 0xfff) == TAG_REG
else 'dir' if (tag & 0xfff) == TAG_DIR
else 'name 0x%02x' % (tag & 0xff), else 'name 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_STRUCT: elif (tag & 0xef00) == TAG_STRUCT:
return '%s%s %d' % ( return '%s%s%s %d' % (
'inlined' if tag == TAG_INLINED 'shrub' if tag & TAG_SHRUB else '',
else 'trunk' if tag == TAG_TRUNK 'inlined' if (tag & 0xfff) == TAG_INLINED
else 'block' if tag == TAG_BLOCK else 'trunk' if (tag & 0xfff) == TAG_TRUNK
else 'btree' if tag == TAG_BTREE else 'block' if (tag & 0xfff) == TAG_BLOCK
else 'mdir' if tag == TAG_MDIR else 'btree' if (tag & 0xfff) == TAG_BTREE
else 'mtree' if tag == TAG_MTREE else 'mdir' if (tag & 0xfff) == TAG_MDIR
else 'mroot' if tag == TAG_MROOT else 'mtree' if (tag & 0xfff) == TAG_MTREE
else 'did' if tag == TAG_DID else 'mroot' if (tag & 0xfff) == TAG_MROOT
else 'did' if (tag & 0xfff) == TAG_DID
else 'struct 0x%02x' % (tag & 0xff), else 'struct 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_UATTR: elif (tag & 0xef00) == TAG_UATTR:
return 'uattr 0x%02x%s %d' % ( return '%suattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_SATTR: elif (tag & 0xef00) == TAG_SATTR:
return 'sattr 0x%02x%s %d' % ( return '%ssattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_CKSUM: elif (tag & 0xff00) == TAG_CKSUM:
return 'cksum%x%s %d' % ( return 'cksum 0x%02x%s %d' % (
1 if tag & 0x1 else 0, tag & 0xff,
' 0x%x' % w if w > 0 else '', ' w%d' % w if w > 0 else '',
size) size)
elif tag == TAG_ECKSUM: elif (tag & 0xff00) == TAG_ECKSUM:
return 'ecksum%s %d' % ( return 'ecksum%s%s %d' % (
' 0x%x' % w if w > 0 else '', ' 0x%02x' % (tag & 0xff) if tag & 0xff else '',
' w%d' % w if w > 0 else '',
size) size)
elif tag & 0x4000: elif tag & TAG_ALT:
return 'alt%s%s 0x%x w%d %s' % ( return 'alt%s%s 0x%x w%d %s' % (
'r' if tag & 0x1000 else 'b', 'r' if tag & TAG_R else 'b',
'gt' if tag & 0x2000 else 'le', 'gt' if tag & TAG_GT else 'le',
tag & 0x0fff, tag & 0x0fff,
w, w,
'0x%x' % (0xffffffff & (off-size)) '0x%x' % (0xffffffff & (off-size))
@@ -223,11 +234,11 @@ def tagrepr(tag, w, size, off=None):
# our core rbyd type # our core rbyd type
class Rbyd: class Rbyd:
def __init__(self, block, data, rev, off, trunk, weight): def __init__(self, block, data, rev, eoff, trunk, weight):
self.block = block self.block = block
self.data = data self.data = data
self.rev = rev self.rev = rev
self.off = off self.eoff = eoff
self.trunk = trunk self.trunk = trunk
self.weight = weight self.weight = weight
self.redund_blocks = [] self.redund_blocks = []
@@ -280,26 +291,27 @@ class Rbyd:
rev = fromle32(data[0:4]) rev = fromle32(data[0:4])
cksum = 0 cksum = 0
cksum_ = crc32c(data[0:4]) cksum_ = crc32c(data[0:4])
off = 0 eoff = 0
j_ = 4 j_ = 4
trunk_ = 0 trunk_ = 0
trunk__ = 0 trunk__ = 0
trunk___ = 0
weight = 0 weight = 0
weight_ = 0 weight_ = 0
weight__ = 0 weight__ = 0
wastrunk = False wastrunk = False
trunkoff = None trunkeoff = None
while j_ < len(data) and (not trunk or off <= trunk): while j_ < len(data) and (not trunk or eoff <= trunk):
v, tag, w, size, d = fromtag(data[j_:]) v, tag, w, size, d = fromtag(data[j_:])
if v != (popc(cksum_) & 1): if v != (popc(cksum_) & 1):
break break
cksum_ = crc32c(data[j_:j_+d], cksum_) cksum_ = crc32c(data[j_:j_+d], cksum_)
j_ += d j_ += d
if not tag & 0x4000 and j_ + size > len(data): if not tag & TAG_ALT and j_ + size > len(data):
break break
# take care of cksums # take care of cksums
if not tag & 0x4000: if not tag & TAG_ALT:
if (tag & 0xff00) != TAG_CKSUM: if (tag & 0xff00) != TAG_CKSUM:
cksum_ = crc32c(data[j_:j_+size], cksum_) cksum_ = crc32c(data[j_:j_+size], cksum_)
# found a cksum? # found a cksum?
@@ -308,36 +320,39 @@ class Rbyd:
if cksum_ != cksum__: if cksum_ != cksum__:
break break
# commit what we have # commit what we have
off = trunkoff if trunkoff else j_ + size eoff = trunkeoff if trunkeoff else j_ + size
cksum = cksum_ cksum = cksum_
trunk_ = trunk__ trunk_ = trunk__
weight = weight_ weight = weight_
# evaluate trunks # evaluate trunks
if (tag & 0xe000) != 0x2000 and ( if (tag & 0xe000) != TAG_CKSUM and (
not trunk or trunk >= j_-d or wastrunk): not trunk or trunk >= j_-d or wastrunk):
# new trunk? # new trunk?
if not wastrunk: if not wastrunk:
wastrunk = True wastrunk = True
trunk__ = j_-d trunk___ = j_-d
weight__ = 0 weight__ = 0
# keep track of weight # keep track of weight
weight__ += w weight__ += w
# end of trunk? # end of trunk?
if not tag & 0x4000: if not tag & TAG_ALT:
wastrunk = False wastrunk = False
# update weight # update trunk/weight unless we found a shrub or an
# explicit trunk (which may be a shrub) is requested
if not tag & TAG_SHRUB or trunk:
trunk__ = trunk___
weight_ = weight__ weight_ = weight__
# keep track of off for best matching trunk # keep track of eoff for best matching trunk
if trunk and j_ + size > trunk: if trunk and j_ + size > trunk:
trunkoff = j_ + size trunkeoff = j_ + size
if not tag & 0x4000: if not tag & TAG_ALT:
j_ += size j_ += size
return cls(block, data, rev, off, trunk_, weight) return cls(block, data, rev, eoff, trunk_, weight)
def lookup(self, rid, tag): def lookup(self, rid, tag):
if not self: if not self:
@@ -353,20 +368,20 @@ class Rbyd:
_, alt, weight_, jump, d = fromtag(self.data[j:]) _, alt, weight_, jump, d = fromtag(self.data[j:])
# found an alt? # found an alt?
if alt & 0x4000: if alt & TAG_ALT:
# follow? # follow?
if ((rid, tag & 0xfff) > (upper-weight_-1, alt & 0xfff) if ((rid, tag & 0xfff) > (upper-weight_-1, alt & 0xfff)
if alt & 0x2000 if alt & TAG_GT
else ((rid, tag & 0xfff) else ((rid, tag & 0xfff)
<= (lower+weight_, alt & 0xfff))): <= (lower+weight_, alt & 0xfff))):
lower += upper-lower-1-weight_ if alt & 0x2000 else 0 lower += upper-lower-1-weight_ if alt & TAG_GT else 0
upper -= upper-lower-1-weight_ if not alt & 0x2000 else 0 upper -= upper-lower-1-weight_ if not alt & TAG_GT else 0
j = j - jump j = j - jump
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(self.data[j+jump+d:]) _, nalt, _, _, _ = fromtag(self.data[j+jump+d:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j+jump, j, True, 'y')) path.append((j+jump, j, True, 'y'))
else: else:
path.append((j+jump, j, True, 'r')) path.append((j+jump, j, True, 'r'))
@@ -375,14 +390,14 @@ class Rbyd:
# stay on path # stay on path
else: else:
lower += weight_ if not alt & 0x2000 else 0 lower += weight_ if not alt & TAG_GT else 0
upper -= weight_ if alt & 0x2000 else 0 upper -= weight_ if alt & TAG_GT else 0
j = j + d j = j + d
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(self.data[j:]) _, nalt, _, _, _ = fromtag(self.data[j:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j-d, j, False, 'y')) path.append((j-d, j, False, 'y'))
else: else:
path.append((j-d, j, False, 'r')) path.append((j-d, j, False, 'r'))
+95 -80
View File
@@ -39,10 +39,13 @@ TAG_MTREE = 0x0314
TAG_MROOT = 0x0318 TAG_MROOT = 0x0318
TAG_DID = 0x031c TAG_DID = 0x031c
TAG_UATTR = 0x0400 TAG_UATTR = 0x0400
TAG_SATTR = 0x0500 TAG_SATTR = 0x0600
TAG_ALT = 0x4000 TAG_SHRUB = 0x1000
TAG_CKSUM = 0x2000 TAG_CKSUM = 0x2000
TAG_ECKSUM = 0x2100 TAG_ECKSUM = 0x2100
TAG_ALT = 0x4000
TAG_GT = 0x2000
TAG_R = 0x1000
# parse some rbyd addr encodings # parse some rbyd addr encodings
@@ -139,78 +142,86 @@ def xxd(data, width=16):
for b in map(chr, data[i:i+width]))) for b in map(chr, data[i:i+width])))
def tagrepr(tag, w, size, off=None): def tagrepr(tag, w, size, off=None):
if tag == TAG_NULL: if (tag & 0xefff) == TAG_NULL:
return 'null%s%s' % ( return '%snull%s%s' % (
'shrub' if tag & TAG_SHRUB else '',
' w%d' % w if w else '', ' w%d' % w if w else '',
' %d' % size if size else '') ' %d' % size if size else '')
elif (tag & 0xff00) == TAG_CONFIG: elif (tag & 0xef00) == TAG_CONFIG:
return '%s%s %d' % ( return '%s%s%s %d' % (
'magic' if tag == TAG_MAGIC 'shrub' if tag & TAG_SHRUB else '',
else 'version' if tag == TAG_VERSION 'magic' if (tag & 0xfff) == TAG_MAGIC
else 'flags' if tag == TAG_FLAGS else 'version' if (tag & 0xfff) == TAG_VERSION
else 'cksumtype' if tag == TAG_CKSUMTYPE else 'flags' if (tag & 0xfff) == TAG_FLAGS
else 'redundtype' if tag == TAG_REDUNDTYPE else 'cksumtype' if (tag & 0xfff) == TAG_CKSUMTYPE
else 'blocklimit' if tag == TAG_BLOCKLIMIT else 'redundtype' if (tag & 0xfff) == TAG_REDUNDTYPE
else 'disklimit' if tag == TAG_DISKLIMIT else 'blocklimit' if (tag & 0xfff) == TAG_BLOCKLIMIT
else 'mleaflimit' if tag == TAG_MLEAFLIMIT else 'disklimit' if (tag & 0xfff) == TAG_DISKLIMIT
else 'sizelimit' if tag == TAG_SIZELIMIT else 'mleaflimit' if (tag & 0xfff) == TAG_MLEAFLIMIT
else 'namelimit' if tag == TAG_NAMELIMIT else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
else 'utaglimit' if tag == TAG_UTAGLIMIT else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
else 'uattrlimit' if tag == TAG_UATTRLIMIT else 'utaglimit' if (tag & 0xfff) == TAG_UTAGLIMIT
else 'uattrlimit' if (tag & 0xfff) == TAG_UATTRLIMIT
else 'config 0x%02x' % (tag & 0xff), else 'config 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_GSTATE: elif (tag & 0xef00) == TAG_GSTATE:
return '%s%s %d' % ( return '%s%s%s %d' % (
'grm' if tag == TAG_GRM 'shrub' if tag & TAG_SHRUB else '',
'grm' if (tag & 0xfff) == TAG_GRM
else 'gstate 0x%02x' % (tag & 0xff), else 'gstate 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_NAME: elif (tag & 0xef00) == TAG_NAME:
return '%s%s %d' % ( return '%s%s%s %d' % (
'branch' if tag == TAG_BRANCH 'shrub' if tag & TAG_SHRUB else '',
else 'bookmark' if tag == TAG_BOOKMARK 'branch' if (tag & 0xfff) == TAG_BRANCH
else 'reg' if tag == TAG_REG else 'bookmark' if (tag & 0xfff) == TAG_BOOKMARK
else 'dir' if tag == TAG_DIR else 'reg' if (tag & 0xfff) == TAG_REG
else 'dir' if (tag & 0xfff) == TAG_DIR
else 'name 0x%02x' % (tag & 0xff), else 'name 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_STRUCT: elif (tag & 0xef00) == TAG_STRUCT:
return '%s%s %d' % ( return '%s%s%s %d' % (
'inlined' if tag == TAG_INLINED 'shrub' if tag & TAG_SHRUB else '',
else 'trunk' if tag == TAG_TRUNK 'inlined' if (tag & 0xfff) == TAG_INLINED
else 'block' if tag == TAG_BLOCK else 'trunk' if (tag & 0xfff) == TAG_TRUNK
else 'btree' if tag == TAG_BTREE else 'block' if (tag & 0xfff) == TAG_BLOCK
else 'mdir' if tag == TAG_MDIR else 'btree' if (tag & 0xfff) == TAG_BTREE
else 'mtree' if tag == TAG_MTREE else 'mdir' if (tag & 0xfff) == TAG_MDIR
else 'mroot' if tag == TAG_MROOT else 'mtree' if (tag & 0xfff) == TAG_MTREE
else 'did' if tag == TAG_DID else 'mroot' if (tag & 0xfff) == TAG_MROOT
else 'did' if (tag & 0xfff) == TAG_DID
else 'struct 0x%02x' % (tag & 0xff), else 'struct 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_UATTR: elif (tag & 0xef00) == TAG_UATTR:
return 'uattr 0x%02x%s %d' % ( return '%suattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_SATTR: elif (tag & 0xef00) == TAG_SATTR:
return 'sattr 0x%02x%s %d' % ( return '%ssattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_CKSUM: elif (tag & 0xff00) == TAG_CKSUM:
return 'cksum%x%s %d' % ( return 'cksum 0x%02x%s %d' % (
1 if tag & 0x1 else 0, tag & 0xff,
' 0x%x' % w if w > 0 else '', ' w%d' % w if w > 0 else '',
size) size)
elif tag == TAG_ECKSUM: elif (tag & 0xff00) == TAG_ECKSUM:
return 'ecksum%s %d' % ( return 'ecksum%s%s %d' % (
' 0x%x' % w if w > 0 else '', ' 0x%02x' % (tag & 0xff) if tag & 0xff else '',
' w%d' % w if w > 0 else '',
size) size)
elif tag & 0x4000: elif tag & TAG_ALT:
return 'alt%s%s 0x%x w%d %s' % ( return 'alt%s%s 0x%x w%d %s' % (
'r' if tag & 0x1000 else 'b', 'r' if tag & TAG_R else 'b',
'gt' if tag & 0x2000 else 'le', 'gt' if tag & TAG_GT else 'le',
tag & 0x0fff, tag & 0x0fff,
w, w,
'0x%x' % (0xffffffff & (off-size)) '0x%x' % (0xffffffff & (off-size))
@@ -225,11 +236,11 @@ TBranch = co.namedtuple('TBranch', 'a, b, d, c')
# our core rbyd type # our core rbyd type
class Rbyd: class Rbyd:
def __init__(self, block, data, rev, off, trunk, weight): def __init__(self, block, data, rev, eoff, trunk, weight):
self.block = block self.block = block
self.data = data self.data = data
self.rev = rev self.rev = rev
self.off = off self.eoff = eoff
self.trunk = trunk self.trunk = trunk
self.weight = weight self.weight = weight
self.redund_blocks = [] self.redund_blocks = []
@@ -282,26 +293,27 @@ class Rbyd:
rev = fromle32(data[0:4]) rev = fromle32(data[0:4])
cksum = 0 cksum = 0
cksum_ = crc32c(data[0:4]) cksum_ = crc32c(data[0:4])
off = 0 eoff = 0
j_ = 4 j_ = 4
trunk_ = 0 trunk_ = 0
trunk__ = 0 trunk__ = 0
trunk___ = 0
weight = 0 weight = 0
weight_ = 0 weight_ = 0
weight__ = 0 weight__ = 0
wastrunk = False wastrunk = False
trunkoff = None trunkeoff = None
while j_ < len(data) and (not trunk or off <= trunk): while j_ < len(data) and (not trunk or eoff <= trunk):
v, tag, w, size, d = fromtag(data[j_:]) v, tag, w, size, d = fromtag(data[j_:])
if v != (popc(cksum_) & 1): if v != (popc(cksum_) & 1):
break break
cksum_ = crc32c(data[j_:j_+d], cksum_) cksum_ = crc32c(data[j_:j_+d], cksum_)
j_ += d j_ += d
if not tag & 0x4000 and j_ + size > len(data): if not tag & TAG_ALT and j_ + size > len(data):
break break
# take care of cksums # take care of cksums
if not tag & 0x4000: if not tag & TAG_ALT:
if (tag & 0xff00) != TAG_CKSUM: if (tag & 0xff00) != TAG_CKSUM:
cksum_ = crc32c(data[j_:j_+size], cksum_) cksum_ = crc32c(data[j_:j_+size], cksum_)
# found a cksum? # found a cksum?
@@ -310,36 +322,39 @@ class Rbyd:
if cksum_ != cksum__: if cksum_ != cksum__:
break break
# commit what we have # commit what we have
off = trunkoff if trunkoff else j_ + size eoff = trunkeoff if trunkeoff else j_ + size
cksum = cksum_ cksum = cksum_
trunk_ = trunk__ trunk_ = trunk__
weight = weight_ weight = weight_
# evaluate trunks # evaluate trunks
if (tag & 0xe000) != 0x2000 and ( if (tag & 0xe000) != TAG_CKSUM and (
not trunk or trunk >= j_-d or wastrunk): not trunk or trunk >= j_-d or wastrunk):
# new trunk? # new trunk?
if not wastrunk: if not wastrunk:
wastrunk = True wastrunk = True
trunk__ = j_-d trunk___ = j_-d
weight__ = 0 weight__ = 0
# keep track of weight # keep track of weight
weight__ += w weight__ += w
# end of trunk? # end of trunk?
if not tag & 0x4000: if not tag & TAG_ALT:
wastrunk = False wastrunk = False
# update weight # update trunk/weight unless we found a shrub or an
# explicit trunk (which may be a shrub) is requested
if not tag & TAG_SHRUB or trunk:
trunk__ = trunk___
weight_ = weight__ weight_ = weight__
# keep track of off for best matching trunk # keep track of eoff for best matching trunk
if trunk and j_ + size > trunk: if trunk and j_ + size > trunk:
trunkoff = j_ + size trunkeoff = j_ + size
if not tag & 0x4000: if not tag & TAG_ALT:
j_ += size j_ += size
return cls(block, data, rev, off, trunk_, weight) return cls(block, data, rev, eoff, trunk_, weight)
def lookup(self, rid, tag): def lookup(self, rid, tag):
if not self: if not self:
@@ -355,20 +370,20 @@ class Rbyd:
_, alt, weight_, jump, d = fromtag(self.data[j:]) _, alt, weight_, jump, d = fromtag(self.data[j:])
# found an alt? # found an alt?
if alt & 0x4000: if alt & TAG_ALT:
# follow? # follow?
if ((rid, tag & 0xfff) > (upper-weight_-1, alt & 0xfff) if ((rid, tag & 0xfff) > (upper-weight_-1, alt & 0xfff)
if alt & 0x2000 if alt & TAG_GT
else ((rid, tag & 0xfff) else ((rid, tag & 0xfff)
<= (lower+weight_, alt & 0xfff))): <= (lower+weight_, alt & 0xfff))):
lower += upper-lower-1-weight_ if alt & 0x2000 else 0 lower += upper-lower-1-weight_ if alt & TAG_GT else 0
upper -= upper-lower-1-weight_ if not alt & 0x2000 else 0 upper -= upper-lower-1-weight_ if not alt & TAG_GT else 0
j = j - jump j = j - jump
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(self.data[j+jump+d:]) _, nalt, _, _, _ = fromtag(self.data[j+jump+d:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j+jump, j, True, 'y')) path.append((j+jump, j, True, 'y'))
else: else:
path.append((j+jump, j, True, 'r')) path.append((j+jump, j, True, 'r'))
@@ -377,14 +392,14 @@ class Rbyd:
# stay on path # stay on path
else: else:
lower += weight_ if not alt & 0x2000 else 0 lower += weight_ if not alt & TAG_GT else 0
upper -= weight_ if alt & 0x2000 else 0 upper -= weight_ if alt & TAG_GT else 0
j = j + d j = j + d
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(self.data[j:]) _, nalt, _, _, _ = fromtag(self.data[j:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j-d, j, False, 'y')) path.append((j-d, j, False, 'y'))
else: else:
path.append((j-d, j, False, 'r')) path.append((j-d, j, False, 'r'))
@@ -1354,7 +1369,7 @@ def main(disk, mroots=None, *,
min(m.ceil(len(data)/4), min(m.ceil(len(data)/4),
3)))[:23] 3)))[:23]
if not args.get('no_truncate') if not args.get('no_truncate')
and not tag & 0x4000 else ''))) and not tag & TAG_ALT else '')))
# show on-disk encoding of tags # show on-disk encoding of tags
if args.get('raw'): if args.get('raw'):
@@ -1365,7 +1380,7 @@ def main(disk, mroots=None, *,
w_width, '', w_width, '',
line)) line))
if args.get('raw') or args.get('no_truncate'): if args.get('raw') or args.get('no_truncate'):
if not tag & 0x4000: if not tag & TAG_ALT:
for o, line in enumerate(xxd(data)): for o, line in enumerate(xxd(data)):
print('%11s: %*s%*s %s' % ( print('%11s: %*s%*s %s' % (
'%04x' % (j+d + o*16), '%04x' % (j+d + o*16),
+161 -118
View File
@@ -48,10 +48,13 @@ TAG_MTREE = 0x0314
TAG_MROOT = 0x0318 TAG_MROOT = 0x0318
TAG_DID = 0x031c TAG_DID = 0x031c
TAG_UATTR = 0x0400 TAG_UATTR = 0x0400
TAG_SATTR = 0x0500 TAG_SATTR = 0x0600
TAG_ALT = 0x4000 TAG_SHRUB = 0x1000
TAG_CKSUM = 0x2000 TAG_CKSUM = 0x2000
TAG_ECKSUM = 0x2100 TAG_ECKSUM = 0x2100
TAG_ALT = 0x4000
TAG_GT = 0x2000
TAG_R = 0x1000
# parse some rbyd addr encodings # parse some rbyd addr encodings
@@ -131,78 +134,86 @@ def xxd(data, width=16):
for b in map(chr, data[i:i+width]))) for b in map(chr, data[i:i+width])))
def tagrepr(tag, w, size, off=None): def tagrepr(tag, w, size, off=None):
if tag == TAG_NULL: if (tag & 0xefff) == TAG_NULL:
return 'null%s%s' % ( return '%snull%s%s' % (
'shrub' if tag & TAG_SHRUB else '',
' w%d' % w if w else '', ' w%d' % w if w else '',
' %d' % size if size else '') ' %d' % size if size else '')
elif (tag & 0xff00) == TAG_CONFIG: elif (tag & 0xef00) == TAG_CONFIG:
return '%s%s %d' % ( return '%s%s%s %d' % (
'magic' if tag == TAG_MAGIC 'shrub' if tag & TAG_SHRUB else '',
else 'version' if tag == TAG_VERSION 'magic' if (tag & 0xfff) == TAG_MAGIC
else 'flags' if tag == TAG_FLAGS else 'version' if (tag & 0xfff) == TAG_VERSION
else 'cksumtype' if tag == TAG_CKSUMTYPE else 'flags' if (tag & 0xfff) == TAG_FLAGS
else 'redundtype' if tag == TAG_REDUNDTYPE else 'cksumtype' if (tag & 0xfff) == TAG_CKSUMTYPE
else 'blocklimit' if tag == TAG_BLOCKLIMIT else 'redundtype' if (tag & 0xfff) == TAG_REDUNDTYPE
else 'disklimit' if tag == TAG_DISKLIMIT else 'blocklimit' if (tag & 0xfff) == TAG_BLOCKLIMIT
else 'mleaflimit' if tag == TAG_MLEAFLIMIT else 'disklimit' if (tag & 0xfff) == TAG_DISKLIMIT
else 'sizelimit' if tag == TAG_SIZELIMIT else 'mleaflimit' if (tag & 0xfff) == TAG_MLEAFLIMIT
else 'namelimit' if tag == TAG_NAMELIMIT else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
else 'utaglimit' if tag == TAG_UTAGLIMIT else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
else 'uattrlimit' if tag == TAG_UATTRLIMIT else 'utaglimit' if (tag & 0xfff) == TAG_UTAGLIMIT
else 'uattrlimit' if (tag & 0xfff) == TAG_UATTRLIMIT
else 'config 0x%02x' % (tag & 0xff), else 'config 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_GSTATE: elif (tag & 0xef00) == TAG_GSTATE:
return '%s%s %d' % ( return '%s%s%s %d' % (
'grm' if tag == TAG_GRM 'shrub' if tag & TAG_SHRUB else '',
'grm' if (tag & 0xfff) == TAG_GRM
else 'gstate 0x%02x' % (tag & 0xff), else 'gstate 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_NAME: elif (tag & 0xef00) == TAG_NAME:
return '%s%s %d' % ( return '%s%s%s %d' % (
'branch' if tag == TAG_BRANCH 'shrub' if tag & TAG_SHRUB else '',
else 'bookmark' if tag == TAG_BOOKMARK 'branch' if (tag & 0xfff) == TAG_BRANCH
else 'reg' if tag == TAG_REG else 'bookmark' if (tag & 0xfff) == TAG_BOOKMARK
else 'dir' if tag == TAG_DIR else 'reg' if (tag & 0xfff) == TAG_REG
else 'dir' if (tag & 0xfff) == TAG_DIR
else 'name 0x%02x' % (tag & 0xff), else 'name 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_STRUCT: elif (tag & 0xef00) == TAG_STRUCT:
return '%s%s %d' % ( return '%s%s%s %d' % (
'inlined' if tag == TAG_INLINED 'shrub' if tag & TAG_SHRUB else '',
else 'trunk' if tag == TAG_TRUNK 'inlined' if (tag & 0xfff) == TAG_INLINED
else 'block' if tag == TAG_BLOCK else 'trunk' if (tag & 0xfff) == TAG_TRUNK
else 'btree' if tag == TAG_BTREE else 'block' if (tag & 0xfff) == TAG_BLOCK
else 'mdir' if tag == TAG_MDIR else 'btree' if (tag & 0xfff) == TAG_BTREE
else 'mtree' if tag == TAG_MTREE else 'mdir' if (tag & 0xfff) == TAG_MDIR
else 'mroot' if tag == TAG_MROOT else 'mtree' if (tag & 0xfff) == TAG_MTREE
else 'did' if tag == TAG_DID else 'mroot' if (tag & 0xfff) == TAG_MROOT
else 'did' if (tag & 0xfff) == TAG_DID
else 'struct 0x%02x' % (tag & 0xff), else 'struct 0x%02x' % (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_UATTR: elif (tag & 0xef00) == TAG_UATTR:
return 'uattr 0x%02x%s %d' % ( return '%suattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_SATTR: elif (tag & 0xef00) == TAG_SATTR:
return 'sattr 0x%02x%s %d' % ( return '%ssattr 0x%02x%s %d' % (
tag & 0xff, 'shrub' if tag & TAG_SHRUB else '',
((tag & 0x100) >> 1) | (tag & 0xff),
' w%d' % w if w else '', ' w%d' % w if w else '',
size) size)
elif (tag & 0xff00) == TAG_CKSUM: elif (tag & 0xff00) == TAG_CKSUM:
return 'cksum%x%s %d' % ( return 'cksum 0x%02x%s %d' % (
1 if tag & 0x1 else 0, tag & 0xff,
' 0x%x' % w if w > 0 else '', ' w%d' % w if w > 0 else '',
size) size)
elif tag == TAG_ECKSUM: elif (tag & 0xff00) == TAG_ECKSUM:
return 'ecksum%s %d' % ( return 'ecksum%s%s %d' % (
' 0x%x' % w if w > 0 else '', ' 0x%02x' % (tag & 0xff) if tag & 0xff else '',
' w%d' % w if w > 0 else '',
size) size)
elif tag & 0x4000: elif tag & TAG_ALT:
return 'alt%s%s 0x%x w%d %s' % ( return 'alt%s%s 0x%x w%d %s' % (
'r' if tag & 0x1000 else 'b', 'r' if tag & TAG_R else 'b',
'gt' if tag & 0x2000 else 'le', 'gt' if tag & TAG_GT else 'le',
tag & 0x0fff, tag & 0x0fff,
w, w,
'0x%x' % (0xffffffff & (off-size)) '0x%x' % (0xffffffff & (off-size))
@@ -212,7 +223,7 @@ def tagrepr(tag, w, size, off=None):
return '0x%04x w%d %d' % (tag, w, size) return '0x%04x w%d %d' % (tag, w, size)
def dbg_log(data, block_size, rev, off, weight, *, def dbg_log(data, block_size, rev, eoff, weight, *,
color=False, color=False,
**args): **args):
cksum = crc32c(data[0:4]) cksum = crc32c(data[0:4])
@@ -221,18 +232,18 @@ def dbg_log(data, block_size, rev, off, weight, *,
if args.get('jumps'): if args.get('jumps'):
jumps = [] jumps = []
j_ = 4 j_ = 4
while j_ < (block_size if args.get('all') else off): while j_ < (block_size if args.get('all') else eoff):
j = j_ j = j_
v, tag, w, size, d = fromtag(data[j_:]) v, tag, w, size, d = fromtag(data[j_:])
j_ += d j_ += d
if not tag & 0x4000: if not tag & TAG_ALT:
j_ += size j_ += size
if tag & 0x4000: if tag & TAG_ALT:
# figure out which alt color # figure out which alt color
if tag & 0x1000: if tag & TAG_R:
_, ntag, _, _, _ = fromtag(data[j_:]) _, ntag, _, _, _ = fromtag(data[j_:])
if ntag & 0x1000: if ntag & TAG_R:
jumps.append((j, j-size, 0, 'y')) jumps.append((j, j-size, 0, 'y'))
else: else:
jumps.append((j, j-size, 0, 'r')) jumps.append((j, j-size, 0, 'r'))
@@ -318,32 +329,32 @@ def dbg_log(data, block_size, rev, off, weight, *,
weight_ = 0 weight_ = 0
wastrunk = False wastrunk = False
j_ = 4 j_ = 4
while j_ < (block_size if args.get('all') else off): while j_ < (block_size if args.get('all') else eoff):
j = j_ j = j_
v, tag, w, size, d = fromtag(data[j_:]) v, tag, w, size, d = fromtag(data[j_:])
j_ += d j_ += d
if not tag & 0x4000: if not tag & TAG_ALT:
j_ += size j_ += size
# evaluate trunks # evaluate trunks
if (tag & 0xe000) != 0x2000: if (tag & 0xe000) != TAG_CKSUM:
if not wastrunk: if not wastrunk:
wastrunk = True wastrunk = True
lower_, upper_ = 0, 0 lower_, upper_ = 0, 0
if (tag & 0xe000) == 0x4000: if (tag & 0xe000) == TAG_ALT:
lower_ += w lower_ += w
else: else:
upper_ += w upper_ += w
if not tag & 0x4000: if not tag & TAG_ALT:
wastrunk = False wastrunk = False
# derive the current tag's rid from alt weights # derive the current tag's rid from alt weights
delta = (lower_+upper_) - weight_ delta = (lower_+upper_) - weight_
weight_ = lower_+upper_ weight_ = lower_+upper_
rid = lower_ + w-1 rid = lower_ + w-1
if (tag & 0xe000) != 0x2000 and not tag & 0x4000: if (tag & 0xe000) != TAG_CKSUM and not tag & TAG_ALT:
# note we ignore out-of-bounds here for debugging # note we ignore out-of-bounds here for debugging
if delta > 0: if delta > 0:
# grow lifetimes # grow lifetimes
@@ -439,7 +450,35 @@ def dbg_log(data, block_size, rev, off, weight, *,
# dynamically size the id field # dynamically size the id field
w_width = 2*m.ceil(m.log10(max(1, weight)+1))+1 #
# we need to do an additional pass to find this since our rbyd weight
# does not include any shrub trees
weight_ = 0
weight__ = 0
wastrunk = False
j_ = 4
while j_ < (block_size if args.get('all') else eoff):
j = j_
v, tag, w, size, d = fromtag(data[j_:])
j_ += d
if not tag & TAG_ALT:
j_ += size
# evaluate trunks
if (tag & 0xe000) != TAG_CKSUM:
if not wastrunk:
wastrunk = True
weight__ = 0
weight__ += w
if not tag & TAG_ALT:
wastrunk = False
# found new weight?
weight_ = max(weight_, weight__)
w_width = 2*m.ceil(m.log10(max(1, weight_)+1))+1
# print revision count # print revision count
if args.get('raw'): if args.get('raw'):
@@ -453,7 +492,7 @@ def dbg_log(data, block_size, rev, off, weight, *,
lower_, upper_ = 0, 0 lower_, upper_ = 0, 0
wastrunk = False wastrunk = False
j_ = 4 j_ = 4
while j_ < (block_size if args.get('all') else off): while j_ < (block_size if args.get('all') else eoff):
notes = [] notes = []
j = j_ j = j_
@@ -464,7 +503,7 @@ def dbg_log(data, block_size, rev, off, weight, *,
j_ += d j_ += d
# take care of cksums # take care of cksums
if not tag & 0x4000: if not tag & TAG_ALT:
if (tag & 0xff00) != TAG_CKSUM: if (tag & 0xff00) != TAG_CKSUM:
cksum = crc32c(data[j_:j_+size], cksum) cksum = crc32c(data[j_:j_+size], cksum)
# found a cksum? # found a cksum?
@@ -475,28 +514,28 @@ def dbg_log(data, block_size, rev, off, weight, *,
j_ += size j_ += size
# evaluate trunks # evaluate trunks
if (tag & 0xe000) != 0x2000: if (tag & 0xe000) != TAG_CKSUM:
if not wastrunk: if not wastrunk:
wastrunk = True wastrunk = True
lower_, upper_ = 0, 0 lower_, upper_ = 0, 0
if (tag & 0xe000) == 0x4000: if (tag & 0xe000) == TAG_ALT:
lower_ += w lower_ += w
else: else:
upper_ += w upper_ += w
if not tag & 0x4000: if not tag & TAG_ALT:
wastrunk = False wastrunk = False
# derive the current tag's rid from alt weights # derive the current tag's rid from alt weights
rid = lower_ + w-1 rid = lower_ + w-1
# show human-readable tag representation # show human-readable tag representation
print('%s%08x:%s %*s%s%*s %-57s%s%s' % ( print('%s%08x:%s %*s%s%*s %-57s%s%s' % (
'\x1b[90m' if color and j >= off else '', '\x1b[90m' if color and j >= eoff else '',
j, j,
'\x1b[m' if color and j >= off else '', '\x1b[m' if color and j >= eoff else '',
lifetime_width, lifetimerepr(j) if args.get('lifetimes') else '', lifetime_width, lifetimerepr(j) if args.get('lifetimes') else '',
'\x1b[90m' if color and j >= off else '', '\x1b[90m' if color and j >= eoff else '',
w_width, '' if (tag & 0xe000) != 0x0000 w_width, '' if (tag & 0xe000) != 0x0000
else '%d-%d' % (rid-(w-1), rid) if w > 1 else '%d-%d' % (rid-(w-1), rid) if w > 1
else rid, else rid,
@@ -505,8 +544,8 @@ def dbg_log(data, block_size, rev, off, weight, *,
' %s' % next(xxd( ' %s' % next(xxd(
data[j+d:j+d+min(size, 8)], 8), '') data[j+d:j+d+min(size, 8)], 8), '')
if not args.get('no_truncate') if not args.get('no_truncate')
and not tag & 0x4000 else ''), and not tag & TAG_ALT else ''),
'\x1b[m' if color and j >= off else '', '\x1b[m' if color and j >= eoff else '',
' (%s)' % ', '.join(notes) if notes ' (%s)' % ', '.join(notes) if notes
else ' %s' % jumprepr(j) else ' %s' % jumprepr(j)
if args.get('jumps') if args.get('jumps')
@@ -516,7 +555,7 @@ def dbg_log(data, block_size, rev, off, weight, *,
# cksum/parity info # cksum/parity info
if args.get('device'): if args.get('device'):
print('%s%8s %*s%*s %-47s %08x %x%s' % ( print('%s%8s %*s%*s %-47s %08x %x%s' % (
'\x1b[90m' if color and j >= off else '', '\x1b[90m' if color and j >= eoff else '',
'', '',
lifetime_width, '', lifetime_width, '',
w_width, '', w_width, '',
@@ -527,31 +566,31 @@ def dbg_log(data, block_size, rev, off, weight, *,
data[j+d+i*4:j+d+min(i*4+4,size)]) data[j+d+i*4:j+d+min(i*4+4,size)])
for i in range(min(m.ceil(size/4), 3)))[:23] for i in range(min(m.ceil(size/4), 3)))[:23]
if not args.get('no_truncate') if not args.get('no_truncate')
and not tag & 0x4000 else ''), and not tag & TAG_ALT else ''),
cksum, cksum,
popc(cksum) & 1, popc(cksum) & 1,
'\x1b[m' if color and j >= off else '')) '\x1b[m' if color and j >= eoff else ''))
# show on-disk encoding of tags # show on-disk encoding of tags
if args.get('raw'): if args.get('raw'):
for o, line in enumerate(xxd(data[j:j+d])): for o, line in enumerate(xxd(data[j:j+d])):
print('%s%8s: %*s%*s %s%s' % ( print('%s%8s: %*s%*s %s%s' % (
'\x1b[90m' if color and j >= off else '', '\x1b[90m' if color and j >= eoff else '',
'%04x' % (j + o*16), '%04x' % (j + o*16),
lifetime_width, '', lifetime_width, '',
w_width, '', w_width, '',
line, line,
'\x1b[m' if color and j >= off else '')) '\x1b[m' if color and j >= eoff else ''))
if args.get('raw') or args.get('no_truncate'): if args.get('raw') or args.get('no_truncate'):
if not tag & 0x4000: if not tag & TAG_ALT:
for o, line in enumerate(xxd(data[j+d:j+d+size])): for o, line in enumerate(xxd(data[j+d:j+d+size])):
print('%s%8s: %*s%*s %s%s' % ( print('%s%8s: %*s%*s %s%s' % (
'\x1b[90m' if color and j >= off else '', '\x1b[90m' if color and j >= eoff else '',
'%04x' % (j+d + o*16), '%04x' % (j+d + o*16),
lifetime_width, '', lifetime_width, '',
w_width, '', w_width, '',
line, line,
'\x1b[m' if color and j >= off else '')) '\x1b[m' if color and j >= eoff else ''))
def dbg_tree(data, block_size, rev, trunk, weight, *, def dbg_tree(data, block_size, rev, trunk, weight, *,
@@ -573,19 +612,19 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
_, alt, w, jump, d = fromtag(data[j:]) _, alt, w, jump, d = fromtag(data[j:])
# found an alt? # found an alt?
if alt & 0x4000: if alt & TAG_ALT:
# follow? # follow?
if ((rid, tag & 0xfff) > (upper-w-1, alt & 0xfff) if ((rid, tag & 0xfff) > (upper-w-1, alt & 0xfff)
if alt & 0x2000 if alt & TAG_GT
else ((rid, tag & 0xfff) <= (lower+w, alt & 0xfff))): else ((rid, tag & 0xfff) <= (lower+w, alt & 0xfff))):
lower += upper-lower-1-w if alt & 0x2000 else 0 lower += upper-lower-1-w if alt & TAG_GT else 0
upper -= upper-lower-1-w if not alt & 0x2000 else 0 upper -= upper-lower-1-w if not alt & TAG_GT else 0
j = j - jump j = j - jump
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(data[j+jump+d:]) _, nalt, _, _, _ = fromtag(data[j+jump+d:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j+jump, j, True, 'y')) path.append((j+jump, j, True, 'y'))
else: else:
path.append((j+jump, j, True, 'r')) path.append((j+jump, j, True, 'r'))
@@ -594,14 +633,14 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
# stay on path # stay on path
else: else:
lower += w if not alt & 0x2000 else 0 lower += w if not alt & TAG_GT else 0
upper -= w if alt & 0x2000 else 0 upper -= w if alt & TAG_GT else 0
j = j + d j = j + d
# figure out which color # figure out which color
if alt & 0x1000: if alt & TAG_R:
_, nalt, _, _, _ = fromtag(data[j:]) _, nalt, _, _, _ = fromtag(data[j:])
if nalt & 0x1000: if nalt & TAG_R:
path.append((j-d, j, False, 'y')) path.append((j-d, j, False, 'y'))
else: else:
path.append((j-d, j, False, 'r')) path.append((j-d, j, False, 'r'))
@@ -782,7 +821,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
' %s' % next(xxd( ' %s' % next(xxd(
data[j+d:j+d+min(size, 8)], 8), '') data[j+d:j+d+min(size, 8)], 8), '')
if not args.get('no_truncate') if not args.get('no_truncate')
and not tag & 0x4000 else ''))) and not tag & TAG_ALT else '')))
# show in-device representation # show in-device representation
if args.get('device'): if args.get('device'):
@@ -797,7 +836,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
data[j+d+i*4:j+d+min(i*4+4,size)]) data[j+d+i*4:j+d+min(i*4+4,size)])
for i in range(min(m.ceil(size/4), 3)))[:23] for i in range(min(m.ceil(size/4), 3)))[:23]
if not args.get('no_truncate') if not args.get('no_truncate')
and not tag & 0x4000 else ''))) and not tag & TAG_ALT else '')))
# show on-disk encoding of tags # show on-disk encoding of tags
if args.get('raw'): if args.get('raw'):
@@ -808,7 +847,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
w_width, '', w_width, '',
line)) line))
if args.get('raw') or args.get('no_truncate'): if args.get('raw') or args.get('no_truncate'):
if not tag & 0x4000: if not tag & TAG_ALT:
for o, line in enumerate(xxd(data[j+d:j+d+size])): for o, line in enumerate(xxd(data[j+d:j+d+size])):
print('%8s: %*s%*s %s' % ( print('%8s: %*s%*s %s' % (
'%04x' % (j+d + o*16), '%04x' % (j+d + o*16),
@@ -861,26 +900,27 @@ def main(disk, blocks=None, *,
rev = fromle32(data[0:4]) rev = fromle32(data[0:4])
cksum = 0 cksum = 0
cksum_ = crc32c(data[0:4]) cksum_ = crc32c(data[0:4])
off = 0 eoff = 0
j_ = 4 j_ = 4
trunk_ = 0 trunk_ = 0
trunk__ = 0 trunk__ = 0
trunk___ = 0
weight = 0 weight = 0
weight_ = 0 weight_ = 0
weight__ = 0 weight__ = 0
wastrunk = False wastrunk = False
trunkoff = None trunkeoff = None
while j_ < len(data) and (not trunk or off <= trunk): while j_ < len(data) and (not trunk or eoff <= trunk):
v, tag, w, size, d = fromtag(data[j_:]) v, tag, w, size, d = fromtag(data[j_:])
if v != (popc(cksum_) & 1): if v != (popc(cksum_) & 1):
break break
cksum_ = crc32c(data[j_:j_+d], cksum_) cksum_ = crc32c(data[j_:j_+d], cksum_)
j_ += d j_ += d
if not tag & 0x4000 and j_ + size > len(data): if not tag & TAG_ALT and j_ + size > len(data):
break break
# take care of cksums # take care of cksums
if not tag & 0x4000: if not tag & TAG_ALT:
if (tag & 0xff00) != TAG_CKSUM: if (tag & 0xff00) != TAG_CKSUM:
cksum_ = crc32c(data[j_:j_+size], cksum_) cksum_ = crc32c(data[j_:j_+size], cksum_)
# found a cksum? # found a cksum?
@@ -889,43 +929,46 @@ def main(disk, blocks=None, *,
if cksum_ != cksum__: if cksum_ != cksum__:
break break
# commit what we have # commit what we have
off = trunkoff if trunkoff else j_ + size eoff = trunkeoff if trunkeoff else j_ + size
cksum = cksum_ cksum = cksum_
trunk_ = trunk__ trunk_ = trunk__
weight = weight_ weight = weight_
# evaluate trunks # evaluate trunks
if (tag & 0xe000) != 0x2000 and ( if (tag & 0xe000) != TAG_CKSUM and (
not trunk or trunk >= j_-d or wastrunk): not trunk or trunk >= j_-d or wastrunk):
# new trunk? # new trunk?
if not wastrunk: if not wastrunk:
wastrunk = True wastrunk = True
trunk__ = j_-d trunk___ = j_-d
weight__ = 0 weight__ = 0
# keep track of weight # keep track of weight
weight__ += w weight__ += w
# end of trunk? # end of trunk?
if not tag & 0x4000: if not tag & TAG_ALT:
wastrunk = False wastrunk = False
# update weight # update trunk/weight unless we found a shrub or an
# explicit trunk (which may be a shrub) is requested
if not tag & TAG_SHRUB or trunk:
trunk__ = trunk___
weight_ = weight__ weight_ = weight__
# keep track of off for best matching trunk # keep track of eoff for best matching trunk
if trunk and j_ + size > trunk: if trunk and j_ + size > trunk:
trunkoff = j_ + size trunkeoff = j_ + size
if not tag & 0x4000: if not tag & TAG_ALT:
j_ += size j_ += size
return rev, off, trunk_, weight return rev, eoff, trunk_, weight
revs, offs, trunks_, weights = [], [], [], [] revs, eoffs, trunks_, weights = [], [], [], []
i = 0 i = 0
for i_, (data, trunk_) in enumerate(zip(datas, trunks)): for i_, (data, trunk_) in enumerate(zip(datas, trunks)):
rev, off, trunk_, weight = fetch(data, trunk_) rev, eoff, trunk_, weight = fetch(data, trunk_)
revs.append(rev) revs.append(rev)
offs.append(off) eoffs.append(eoff)
trunks_.append(trunk_) trunks_.append(trunk_)
weights.append(weight) weights.append(weight)
@@ -937,8 +980,8 @@ def main(disk, blocks=None, *,
i = i_ i = i_
# print contents of the winning metadata block # print contents of the winning metadata block
block, data, rev, off, trunk_, weight = ( block, data, rev, eoff, trunk_, weight = (
blocks[i], datas[i], revs[i], offs[i], trunks_[i], weights[i]) blocks[i], datas[i], revs[i], eoffs[i], trunks_[i], weights[i])
print('rbyd %s, rev %d, size %d, weight %d' % ( print('rbyd %s, rev %d, size %d, weight %d' % (
'0x%x.%x' % (block, trunk_) '0x%x.%x' % (block, trunk_)
@@ -948,10 +991,10 @@ def main(disk, blocks=None, *,
','.join('%x' % blocks[(i+1+j) % len(blocks)] ','.join('%x' % blocks[(i+1+j) % len(blocks)]
for j in range(len(blocks)-1)), for j in range(len(blocks)-1)),
trunk_), trunk_),
rev, off, weight)) rev, eoff, weight))
if args.get('log'): if args.get('log'):
dbg_log(data, block_size, rev, off, weight, dbg_log(data, block_size, rev, eoff, weight,
color=color, color=color,
**args) **args)
else: else:
@@ -959,7 +1002,7 @@ def main(disk, blocks=None, *,
color=color, color=color,
**args) **args)
if args.get('error_on_corrupt') and off == 0: if args.get('error_on_corrupt') and eoff == 0:
sys.exit(2) sys.exit(2)