forked from Imagelibrary/littlefs
Updated dbg scripts with changes, adopted mbid.mrid in debug prints
This format for mids is a compromise in readability vs debugability. For example, if our mbid weight is 256 (4KiB blocks), the 19th entry in the second mdir would be the raw integer 275. With this mid format, we would print it as 256.19. The idea is to make it easy to see it's the 19th entry in the mdir while still making it relatively easy to see that 256.19 and 275 are equivalent when debugging. --- The scripts also took some tweaking due to the mid change. Tried to keep the names consistent, but I don't think it's worthwhile to change too much of the scripts while they are working.
This commit is contained in:
77
lfs.c
77
lfs.c
@@ -5248,10 +5248,12 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_DEBUG("Splitting mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"} "
|
LFS_DEBUG("Splitting mdir %"PRId32".%"PRId32" "
|
||||||
"-> 0x{%"PRIx32",%"PRIx32"}"
|
"0x{%"PRIx32",%"PRIx32"} "
|
||||||
", 0x{%"PRIx32",%"PRIx32"}",
|
"-> 0x{%"PRIx32",%"PRIx32"}, "
|
||||||
mdir->mid,
|
"0x{%"PRIx32",%"PRIx32"}",
|
||||||
|
mdir->mid & lfsr_mbidmask(lfs),
|
||||||
|
mdir->mid & lfsr_mridmask(lfs),
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1],
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1],
|
||||||
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1],
|
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1],
|
||||||
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
|
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
|
||||||
@@ -5261,11 +5263,15 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
|
|
||||||
// both siblings reduced to zero
|
// both siblings reduced to zero
|
||||||
if (mdir_.u.m.weight == 0 && msibling_.u.m.weight == 0) {
|
if (mdir_.u.m.weight == 0 && msibling_.u.m.weight == 0) {
|
||||||
LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
|
LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" "
|
||||||
mdir_.mid,
|
"0x{%"PRIx32",%"PRIx32"}",
|
||||||
|
mdir_.mid & lfsr_mbidmask(lfs),
|
||||||
|
mdir_.mid & lfsr_mridmask(lfs),
|
||||||
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
|
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
|
||||||
LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
|
LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" "
|
||||||
msibling_.mid,
|
"0x{%"PRIx32",%"PRIx32"}",
|
||||||
|
msibling_.mid & lfsr_mbidmask(lfs),
|
||||||
|
msibling_.mid & lfsr_mridmask(lfs),
|
||||||
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
|
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
|
||||||
// mark as dropped
|
// mark as dropped
|
||||||
mdir_.u.r.rbyd.trunk = 0;
|
mdir_.u.r.rbyd.trunk = 0;
|
||||||
@@ -5281,8 +5287,10 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
|
|
||||||
// one sibling reduced to zero
|
// one sibling reduced to zero
|
||||||
} else if (msibling_.u.m.weight == 0) {
|
} else if (msibling_.u.m.weight == 0) {
|
||||||
LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
|
LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" "
|
||||||
msibling_.mid,
|
"0x{%"PRIx32",%"PRIx32"}",
|
||||||
|
msibling_.mid & lfsr_mbidmask(lfs),
|
||||||
|
msibling_.mid & lfsr_mridmask(lfs),
|
||||||
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
|
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
|
||||||
|
|
||||||
// mark as dropped
|
// mark as dropped
|
||||||
@@ -5305,8 +5313,10 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
|
|
||||||
// other sibling reduced to zero
|
// other sibling reduced to zero
|
||||||
} else if (mdir_.u.m.weight == 0) {
|
} else if (mdir_.u.m.weight == 0) {
|
||||||
LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
|
LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" "
|
||||||
mdir_.mid,
|
"0x{%"PRIx32",%"PRIx32"}",
|
||||||
|
mdir_.mid & lfsr_mbidmask(lfs),
|
||||||
|
mdir_.mid & lfsr_mridmask(lfs),
|
||||||
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
|
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
|
||||||
|
|
||||||
// mark as dropped
|
// mark as dropped
|
||||||
@@ -5379,8 +5389,10 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
} else if (mdir_.u.m.weight == 0
|
} else if (mdir_.u.m.weight == 0
|
||||||
// unless we are an mroot
|
// unless we are an mroot
|
||||||
&& !(mdir->mid == -1 || lfsr_mtree_isinlined(lfs))) {
|
&& !(mdir->mid == -1 || lfsr_mtree_isinlined(lfs))) {
|
||||||
LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
|
LFS_DEBUG("Dropping mdir %"PRId32".%"PRId32" "
|
||||||
mdir->mid,
|
"0x{%"PRIx32",%"PRIx32"}",
|
||||||
|
mdir->mid & lfsr_mbidmask(lfs),
|
||||||
|
mdir->mid & lfsr_mridmask(lfs),
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
// mark as dropped
|
// mark as dropped
|
||||||
@@ -5406,9 +5418,10 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
|
|
||||||
// relocate a normal mdir
|
// relocate a normal mdir
|
||||||
} else {
|
} else {
|
||||||
LFS_DEBUG("Relocating mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"} "
|
LFS_DEBUG("Relocating mdir %"PRId32".%"PRId32" "
|
||||||
"-> 0x{%"PRIx32",%"PRIx32"}",
|
"0x{%"PRIx32",%"PRIx32"} -> 0x{%"PRIx32",%"PRIx32"}",
|
||||||
mdir->mid,
|
mdir->mid & lfsr_mbidmask(lfs),
|
||||||
|
mdir->mid & lfsr_mridmask(lfs),
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1],
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1],
|
||||||
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
|
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -6564,9 +6577,18 @@ static int lfsr_mountinited(lfs_t *lfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lfsr_grm_hasrm(&lfs->grm)) {
|
if (lfsr_grm_hasrm(&lfs->grm)) {
|
||||||
LFS_DEBUG("Found pending grm %"PRId32" %"PRId32,
|
if (lfsr_grm_count(&lfs->grm) == 2) {
|
||||||
lfs->grm.rms[0],
|
LFS_DEBUG("Found pending grm "
|
||||||
lfs->grm.rms[1]);
|
"%"PRId32".%"PRId32" %"PRId32".%"PRId32,
|
||||||
|
lfs->grm.rms[0] & lfsr_mbidmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mridmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mbidmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mridmask(lfs));
|
||||||
|
} else if (lfsr_grm_count(&lfs->grm) == 1) {
|
||||||
|
LFS_DEBUG("Found pending grm %"PRId32".%"PRId32,
|
||||||
|
lfs->grm.rms[0] & lfsr_mbidmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mridmask(lfs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -7380,9 +7402,18 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) {
|
|||||||
|
|
||||||
// fix pending grms
|
// fix pending grms
|
||||||
if (lfsr_grm_hasrm(&lfs->grm)) {
|
if (lfsr_grm_hasrm(&lfs->grm)) {
|
||||||
LFS_DEBUG("Fixing grm %"PRId32" %"PRId32,
|
if (lfsr_grm_count(&lfs->grm) == 2) {
|
||||||
lfs->grm.rms[0],
|
LFS_DEBUG("Fixing pending grm "
|
||||||
lfs->grm.rms[1]);
|
"%"PRId32".%"PRId32" %"PRId32".%"PRId32,
|
||||||
|
lfs->grm.rms[0] & lfsr_mbidmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mridmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mbidmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mridmask(lfs));
|
||||||
|
} else if (lfsr_grm_count(&lfs->grm) == 1) {
|
||||||
|
LFS_DEBUG("Fixing pending grm %"PRId32".%"PRId32,
|
||||||
|
lfs->grm.rms[0] & lfsr_mbidmask(lfs),
|
||||||
|
lfs->grm.rms[0] & lfsr_mridmask(lfs));
|
||||||
|
}
|
||||||
|
|
||||||
int err = lfsr_fs_fixgrm(lfs);
|
int err = lfsr_fs_fixgrm(lfs);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -812,7 +812,7 @@ def main(disk, roots=None, *,
|
|||||||
print('%-9s %*s%-*s %-22s %s' % (
|
print('%-9s %*s%-*s %-22s %s' % (
|
||||||
'rbyd',
|
'rbyd',
|
||||||
t_width, '',
|
t_width, '',
|
||||||
w_width, 'ids',
|
w_width, 'bid',
|
||||||
'tag',
|
'tag',
|
||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ class Rbyd:
|
|||||||
return not tags, bid + (rid_-rid), w, rbyd, rid_, tags, path
|
return not tags, bid + (rid_-rid), w, rbyd, rid_, tags, path
|
||||||
|
|
||||||
# mtree lookup with this rbyd as the mroot
|
# mtree lookup with this rbyd as the mroot
|
||||||
def mtree_lookup(self, f, block_size, mid):
|
def mtree_lookup(self, f, block_size, mbid):
|
||||||
# have mtree?
|
# have mtree?
|
||||||
done, rid, tag, w, j, d, data, _ = self.lookup(-1, TAG_MTREE)
|
done, rid, tag, w, j, d, data, _ = self.lookup(-1, TAG_MTREE)
|
||||||
if not done and rid == -1 and tag == TAG_MTREE:
|
if not done and rid == -1 and tag == TAG_MTREE:
|
||||||
@@ -462,39 +462,39 @@ class Rbyd:
|
|||||||
mtree = Rbyd.fetch(f, block_size, block, trunk)
|
mtree = Rbyd.fetch(f, block_size, block, trunk)
|
||||||
# corrupted?
|
# corrupted?
|
||||||
if not mtree:
|
if not mtree:
|
||||||
return None
|
return True, -1, 0, None
|
||||||
|
|
||||||
# lookup our mid
|
# lookup our mbid
|
||||||
done, mid, w, rbyd, rid, tags, path = mtree.btree_lookup(
|
done, mbid, mw, rbyd, rid, tags, path = mtree.btree_lookup(
|
||||||
f, block_size, mid)
|
f, block_size, mbid)
|
||||||
if done:
|
if done:
|
||||||
return None
|
return True, -1, 0, None
|
||||||
|
|
||||||
mdir = next(((tag, j, d, data)
|
mdir = next(((tag, j, d, data)
|
||||||
for tag, j, d, data in tags
|
for tag, j, d, data in tags
|
||||||
if tag == TAG_MDIR),
|
if tag == TAG_MDIR),
|
||||||
None)
|
None)
|
||||||
if not mdir:
|
if not mdir:
|
||||||
return None
|
return True, -1, 0, None
|
||||||
|
|
||||||
# fetch the mdir
|
# fetch the mdir
|
||||||
_, _, _, data = mdir
|
_, _, _, data = mdir
|
||||||
blocks = frommdir(data)
|
blocks = frommdir(data)
|
||||||
return Rbyd.fetch(f, block_size, blocks)
|
return False, mbid, mw, Rbyd.fetch(f, block_size, blocks)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# have mdir?
|
# have mdir?
|
||||||
done, rid, tag, w, j, _, data, _ = self.lookup(-1, TAG_MDIR)
|
done, rid, tag, w, j, _, data, _ = self.lookup(-1, TAG_MDIR)
|
||||||
if not done and rid == -1 and tag == TAG_MDIR:
|
if not done and rid == -1 and tag == TAG_MDIR:
|
||||||
blocks = frommdir(data)
|
blocks = frommdir(data)
|
||||||
return Rbyd.fetch(f, block_size, blocks)
|
return False, 0, 0, Rbyd.fetch(f, block_size, blocks)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# I guess we're inlined?
|
# I guess we're inlined?
|
||||||
if mid == -1:
|
if mbid == -1:
|
||||||
return self
|
return False, -1, 0, self
|
||||||
else:
|
else:
|
||||||
return None
|
return True, -1, 0, None
|
||||||
|
|
||||||
# lookup by name
|
# lookup by name
|
||||||
def namelookup(self, did, name):
|
def namelookup(self, did, name):
|
||||||
@@ -564,7 +564,7 @@ class Rbyd:
|
|||||||
return False, -1, None, -1, 0, 0
|
return False, -1, None, -1, 0, 0
|
||||||
|
|
||||||
# lookup our name in the mtree
|
# lookup our name in the mtree
|
||||||
mid, tag_, w, data = mtree.btree_namelookup(
|
mbid, tag_, mw, data = mtree.btree_namelookup(
|
||||||
f, block_size, did, name)
|
f, block_size, did, name)
|
||||||
if tag_ != TAG_MDIR:
|
if tag_ != TAG_MDIR:
|
||||||
return False, -1, None, -1, 0, 0
|
return False, -1, None, -1, 0, 0
|
||||||
@@ -578,22 +578,24 @@ class Rbyd:
|
|||||||
done, rid, tag, w, j, _, data, _ = self.lookup(-1, TAG_MDIR)
|
done, rid, tag, w, j, _, data, _ = self.lookup(-1, TAG_MDIR)
|
||||||
if not done and rid == -1 and tag == TAG_MDIR:
|
if not done and rid == -1 and tag == TAG_MDIR:
|
||||||
blocks = frommdir(data)
|
blocks = frommdir(data)
|
||||||
mid = 0
|
mbid = 0
|
||||||
|
mw = 0
|
||||||
mdir = Rbyd.fetch(f, block_size, blocks)
|
mdir = Rbyd.fetch(f, block_size, blocks)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# I guess we're inlined?
|
# I guess we're inlined?
|
||||||
mid = -1
|
mbid = -1
|
||||||
|
mw = 0
|
||||||
mdir = self
|
mdir = self
|
||||||
|
|
||||||
# lookup name in our mdir
|
# lookup name in our mdir
|
||||||
found, rid, tag, w = mdir.namelookup(did, name)
|
found, rid, tag, w = mdir.namelookup(did, name)
|
||||||
return found, mid, mdir, rid, tag, w
|
return found, mbid, mw, mdir, rid, tag, w
|
||||||
|
|
||||||
# iterate through a directory assuming this is the mtree root
|
# iterate through a directory assuming this is the mtree root
|
||||||
def mtree_dir(self, f, block_size, did):
|
def mtree_dir(self, f, block_size, did):
|
||||||
# lookup the bookmark
|
# lookup the bookmark
|
||||||
found, mid, mdir, rid, tag, w = self.mtree_namelookup(
|
found, mbid, mw, mdir, rid, tag, w = self.mtree_namelookup(
|
||||||
f, block_size, did, b'')
|
f, block_size, did, b'')
|
||||||
# iterate through all files until the next bookmark
|
# iterate through all files until the next bookmark
|
||||||
while found:
|
while found:
|
||||||
@@ -611,15 +613,15 @@ class Rbyd:
|
|||||||
break
|
break
|
||||||
|
|
||||||
# yield what we've found
|
# yield what we've found
|
||||||
yield name_, mid, mdir, rid, tag, w
|
yield name_, mbid, mw, mdir, rid, tag, w
|
||||||
|
|
||||||
rid += w
|
rid += w
|
||||||
if rid >= mdir.weight:
|
if rid >= mdir.weight:
|
||||||
rid -= mdir.weight
|
rid -= mdir.weight
|
||||||
mid += 1
|
mbid += 1
|
||||||
|
|
||||||
mdir = self.mtree_lookup(f, block_size, mid)
|
done, mbid, mw, mdir = self.mtree_lookup(f, block_size, mbid)
|
||||||
if not mdir:
|
if done:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@@ -651,11 +653,12 @@ def superconfig(mroot):
|
|||||||
|
|
||||||
# collect gstate
|
# collect gstate
|
||||||
class GState:
|
class GState:
|
||||||
def __init__(self):
|
def __init__(self, block_size):
|
||||||
self.gstate = {}
|
self.gstate = {}
|
||||||
self.gdelta = {}
|
self.gdelta = {}
|
||||||
|
self.block_size = block_size
|
||||||
|
|
||||||
def xor(self, mid, mdir):
|
def xor(self, mbid, mw, mdir):
|
||||||
tag = TAG_GSTATE-0x1
|
tag = TAG_GSTATE-0x1
|
||||||
while True:
|
while True:
|
||||||
done, rid, tag, w, j, d, data, _ = mdir.lookup(-1, tag+0x1)
|
done, rid, tag, w, j, d, data, _ = mdir.lookup(-1, tag+0x1)
|
||||||
@@ -665,7 +668,7 @@ class GState:
|
|||||||
# keep track of gdeltas
|
# keep track of gdeltas
|
||||||
if tag not in self.gdelta:
|
if tag not in self.gdelta:
|
||||||
self.gdelta[tag] = []
|
self.gdelta[tag] = []
|
||||||
self.gdelta[tag].append((mid, mdir, j, d, data))
|
self.gdelta[tag].append((mbid, mw, mdir, j, d, data))
|
||||||
|
|
||||||
# xor gstate
|
# xor gstate
|
||||||
if tag not in self.gstate:
|
if tag not in self.gstate:
|
||||||
@@ -679,6 +682,10 @@ class GState:
|
|||||||
if TAG_GRM not in self.gstate:
|
if TAG_GRM not in self.gstate:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# derive the mbid/mrid masks from the block_size
|
||||||
|
mridmask = (1 << m.ceil(m.log2(self.block_size // 16)))-1
|
||||||
|
mbidmask = ~mridmask
|
||||||
|
|
||||||
data = self.gstate[TAG_GRM]
|
data = self.gstate[TAG_GRM]
|
||||||
d = 0
|
d = 0
|
||||||
count, d_ = fromleb128(data[d:]); d += d_
|
count, d_ = fromleb128(data[d:]); d += d_
|
||||||
@@ -686,23 +693,25 @@ class GState:
|
|||||||
if count <= 2:
|
if count <= 2:
|
||||||
for _ in range(count):
|
for _ in range(count):
|
||||||
mid, d_ = fromleb128(data[d:]); d += d_
|
mid, d_ = fromleb128(data[d:]); d += d_
|
||||||
rid, d_ = fromleb128(data[d:]); d += d_
|
rms.append((mid & mbidmask, mid & mridmask))
|
||||||
rms.append((mid, rid))
|
|
||||||
return rms
|
return rms
|
||||||
|
|
||||||
def grepr(tag, data):
|
def grepr(tag, data, block_size):
|
||||||
if tag == TAG_GRM:
|
if tag == TAG_GRM:
|
||||||
|
# derive the mbid/mrid masks from the block_size
|
||||||
|
mridmask = (1 << m.ceil(m.log2(block_size // 16)))-1
|
||||||
|
mbidmask = ~mridmask
|
||||||
|
|
||||||
d = 0
|
d = 0
|
||||||
count, d_ = fromleb128(data[d:]); d += d_
|
count, d_ = fromleb128(data[d:]); d += d_
|
||||||
rms = []
|
rms = []
|
||||||
if count <= 2:
|
if count <= 2:
|
||||||
for _ in range(count):
|
for _ in range(count):
|
||||||
mid, d_ = fromleb128(data[d:]); d += d_
|
mid, d_ = fromleb128(data[d:]); d += d_
|
||||||
rid, d_ = fromleb128(data[d:]); d += d_
|
rms.append((mid & mbidmask, mid & mridmask))
|
||||||
rms.append((mid, rid))
|
|
||||||
return 'grm %s' % (
|
return 'grm %s' % (
|
||||||
'none' if count == 0
|
'none' if count == 0
|
||||||
else ' '.join('%d.%d' % (mid, rid) for mid, rid in rms)
|
else ' '.join('%d.%d' % (mbid, rid) for mbid, rid in rms)
|
||||||
if count <= 2
|
if count <= 2
|
||||||
else '0x%x' % count)
|
else '0x%x' % count)
|
||||||
else:
|
else:
|
||||||
@@ -763,9 +772,9 @@ def main(disk, mroots=None, *,
|
|||||||
mweight = 0
|
mweight = 0
|
||||||
rweight = 0
|
rweight = 0
|
||||||
corrupted = False
|
corrupted = False
|
||||||
gstate = GState()
|
gstate = GState(block_size)
|
||||||
config = {}
|
config = {}
|
||||||
dir_dids = [(0, b'', -1, None, -1, TAG_DID, 0)]
|
dir_dids = [(0, b'', -1, 0, None, -1, TAG_DID, 0)]
|
||||||
bookmark_dids = []
|
bookmark_dids = []
|
||||||
|
|
||||||
mroot = Rbyd.fetch(f, block_size, mroots)
|
mroot = Rbyd.fetch(f, block_size, mroots)
|
||||||
@@ -778,7 +787,7 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
rweight = max(rweight, mroot.weight)
|
rweight = max(rweight, mroot.weight)
|
||||||
# yes we get gstate from all mroots
|
# yes we get gstate from all mroots
|
||||||
gstate.xor(-1, mroot)
|
gstate.xor(-1, 0, mroot)
|
||||||
# get the superconfig
|
# get the superconfig
|
||||||
config = superconfig(mroot)
|
config = superconfig(mroot)
|
||||||
|
|
||||||
@@ -787,11 +796,11 @@ def main(disk, mroots=None, *,
|
|||||||
if tag == TAG_DID:
|
if tag == TAG_DID:
|
||||||
did, d = fromleb128(data)
|
did, d = fromleb128(data)
|
||||||
dir_dids.append(
|
dir_dids.append(
|
||||||
(did, data[d:], -1, mroot, rid, tag, w))
|
(did, data[d:], -1, 0, mroot, rid, tag, w))
|
||||||
elif tag == TAG_BOOKMARK:
|
elif tag == TAG_BOOKMARK:
|
||||||
did, d = fromleb128(data)
|
did, d = fromleb128(data)
|
||||||
bookmark_dids.append(
|
bookmark_dids.append(
|
||||||
(did, data[d:], -1, mroot, rid, tag, w))
|
(did, data[d:], -1, 0, mroot, rid, tag, w))
|
||||||
|
|
||||||
# fetch the next mroot
|
# fetch the next mroot
|
||||||
done, rid, tag, w, j, d, data, _ = mroot.lookup(-1, TAG_MROOT)
|
done, rid, tag, w, j, d, data, _ = mroot.lookup(-1, TAG_MROOT)
|
||||||
@@ -821,11 +830,11 @@ def main(disk, mroots=None, *,
|
|||||||
if tag == TAG_DID:
|
if tag == TAG_DID:
|
||||||
did, d = fromleb128(data)
|
did, d = fromleb128(data)
|
||||||
dir_dids.append((
|
dir_dids.append((
|
||||||
did, data[d:], 0, mdir, rid, tag, w))
|
did, data[d:], 0, 0, mdir, rid, tag, w))
|
||||||
elif tag == TAG_BOOKMARK:
|
elif tag == TAG_BOOKMARK:
|
||||||
did, d = fromleb128(data)
|
did, d = fromleb128(data)
|
||||||
bookmark_dids.append((
|
bookmark_dids.append((
|
||||||
did, data[d:], 0, mdir, rid, tag, w))
|
did, data[d:], 0, 0, mdir, rid, tag, w))
|
||||||
|
|
||||||
# fetch the actual mtree, if there is one
|
# fetch the actual mtree, if there is one
|
||||||
mtree = None
|
mtree = None
|
||||||
@@ -837,10 +846,10 @@ def main(disk, mroots=None, *,
|
|||||||
mweight = w
|
mweight = w
|
||||||
|
|
||||||
# traverse entries
|
# traverse entries
|
||||||
mid = -1
|
mbid = -1
|
||||||
while True:
|
while True:
|
||||||
done, mid, w, rbyd, rid, tags, path = mtree.btree_lookup(
|
done, mbid, mw, rbyd, rid, tags, path = mtree.btree_lookup(
|
||||||
f, block_size, mid+1)
|
f, block_size, mbid+1)
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -865,26 +874,30 @@ def main(disk, mroots=None, *,
|
|||||||
corrupted = True
|
corrupted = True
|
||||||
else:
|
else:
|
||||||
rweight = max(rweight, mdir_.weight)
|
rweight = max(rweight, mdir_.weight)
|
||||||
gstate.xor(mid, mdir_)
|
gstate.xor(mbid, mw, mdir_)
|
||||||
|
|
||||||
# find any dids
|
# find any dids
|
||||||
for rid, tag, w, j, d, data in mdir_:
|
for rid, tag, w, j, d, data in mdir_:
|
||||||
if tag == TAG_DID:
|
if tag == TAG_DID:
|
||||||
did, d = fromleb128(data)
|
did, d = fromleb128(data)
|
||||||
dir_dids.append((
|
dir_dids.append((
|
||||||
did, data[d:], mid, mdir_, rid, tag, w))
|
did, data[d:],
|
||||||
|
mbid, mw, mdir_, rid, tag, w))
|
||||||
elif tag == TAG_BOOKMARK:
|
elif tag == TAG_BOOKMARK:
|
||||||
did, d = fromleb128(data)
|
did, d = fromleb128(data)
|
||||||
bookmark_dids.append((
|
bookmark_dids.append((
|
||||||
did, data[d:], mid, mdir_, rid, tag, w))
|
did, data[d:],
|
||||||
|
mbid, mw, mdir_, rid, tag, w))
|
||||||
|
|
||||||
# remove grms from our found dids, we treat these as already deleted
|
# remove grms from our found dids, we treat these as already deleted
|
||||||
grmed_dir_dids = {did_
|
grmed_dir_dids = {did_
|
||||||
for (did_, name_, mid_, mdir_, rid_, tag_, w_) in dir_dids
|
for (did_, name_, mbid_, mw_, mdir_, rid_, tag_, w_)
|
||||||
if (max(mid_, 0), rid_) not in gstate.grm}
|
in dir_dids
|
||||||
|
if (max(mbid_-max(mw_-1, 0), 0), rid_) not in gstate.grm}
|
||||||
grmed_bookmark_dids = {did_
|
grmed_bookmark_dids = {did_
|
||||||
for (did_, name_, mid_, mdir_, rid_, tag_, w_) in bookmark_dids
|
for (did_, name_, mbid_, mw_, mdir_, rid_, tag_, w_)
|
||||||
if (max(mid_, 0), rid_) not in gstate.grm}
|
in bookmark_dids
|
||||||
|
if (max(mbid_-max(mw_-1, 0), 0), rid_) not in gstate.grm}
|
||||||
|
|
||||||
# treat the filesystem as corrupted if our dirs and bookmarks are
|
# treat the filesystem as corrupted if our dirs and bookmarks are
|
||||||
# mismatched, this should never happen unless there's a bug
|
# mismatched, this should never happen unless there's a bug
|
||||||
@@ -902,7 +915,7 @@ def main(disk, mroots=None, *,
|
|||||||
def rec_f_width(did, depth):
|
def rec_f_width(did, depth):
|
||||||
depth_ = 0
|
depth_ = 0
|
||||||
width_ = 0
|
width_ = 0
|
||||||
for name, mid, mdir, rid, tag, w in mroot.mtree_dir(
|
for name, mbid, mw, mdir, rid, tag, w in mroot.mtree_dir(
|
||||||
f, block_size, did):
|
f, block_size, did):
|
||||||
width_ = max(width_, len(name))
|
width_ = max(width_, len(name))
|
||||||
# recurse?
|
# recurse?
|
||||||
@@ -936,13 +949,13 @@ def main(disk, mroots=None, *,
|
|||||||
if dtree:
|
if dtree:
|
||||||
print('%-11s %-*s %-*s %s' % (
|
print('%-11s %-*s %-*s %s' % (
|
||||||
'mdir',
|
'mdir',
|
||||||
w_width, 'ids',
|
w_width, 'mid',
|
||||||
f_width, 'name',
|
f_width, 'name',
|
||||||
'type'))
|
'type'))
|
||||||
else:
|
else:
|
||||||
print('%-11s %-*s %-22s %s' % (
|
print('%-11s %-*s %-22s %s' % (
|
||||||
'mdir',
|
'mdir',
|
||||||
w_width, 'ids',
|
w_width, 'mid',
|
||||||
'tag',
|
'tag',
|
||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
@@ -985,7 +998,7 @@ def main(disk, mroots=None, *,
|
|||||||
print('%12s %-*s %s' % (
|
print('%12s %-*s %s' % (
|
||||||
'gstate:' if i == 0 else '',
|
'gstate:' if i == 0 else '',
|
||||||
w_width + 23,
|
w_width + 23,
|
||||||
grepr(tag, data),
|
grepr(tag, data, block_size),
|
||||||
next(xxd(data, 8), '')
|
next(xxd(data, 8), '')
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|
||||||
@@ -1014,13 +1027,13 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# print gdeltas?
|
# print gdeltas?
|
||||||
if args.get('gdelta'):
|
if args.get('gdelta'):
|
||||||
for mid, mdir, j, d, data in gstate.gdelta[tag]:
|
for mbid, mw, mdir, j, d, data in gstate.gdelta[tag]:
|
||||||
print('%s{%s}: %*s %-22s %s%s' % (
|
print('%s{%s}: %*s %-22s %s%s' % (
|
||||||
'\x1b[90m' if color else '',
|
'\x1b[90m' if color else '',
|
||||||
','.join('%04x' % block
|
','.join('%04x' % block
|
||||||
for block in it.chain([mdir.block],
|
for block in it.chain([mdir.block],
|
||||||
mdir.redund_blocks)),
|
mdir.redund_blocks)),
|
||||||
w_width, mid,
|
w_width, mbid-max(mw-1, 0),
|
||||||
tagrepr(tag, 0, len(data)),
|
tagrepr(tag, 0, len(data)),
|
||||||
next(xxd(data, 8), '')
|
next(xxd(data, 8), '')
|
||||||
if not args.get('no_truncate') else '',
|
if not args.get('no_truncate') else '',
|
||||||
@@ -1060,39 +1073,40 @@ def main(disk, mroots=None, *,
|
|||||||
# print dtree?
|
# print dtree?
|
||||||
if dtree:
|
if dtree:
|
||||||
# only show mdir on change
|
# only show mdir on change
|
||||||
pmid = None
|
pmbid = None
|
||||||
# recursively print directories
|
# recursively print directories
|
||||||
def rec_dir(did, depth, prefixes=('', '', '', '')):
|
def rec_dir(did, depth, prefixes=('', '', '', '')):
|
||||||
nonlocal pmid
|
nonlocal pmbid
|
||||||
# collect all entries first so we know when the dir ends
|
# collect all entries first so we know when the dir ends
|
||||||
dir = []
|
dir = []
|
||||||
for name, mid, mdir, rid, tag, w in mroot.mtree_dir(
|
for name, mbid, mw, mdir, rid, tag, w in mroot.mtree_dir(
|
||||||
f, block_size, did):
|
f, block_size, did):
|
||||||
if not args.get('all'):
|
if not args.get('all'):
|
||||||
# skip bookmarks
|
# skip bookmarks
|
||||||
if tag == TAG_BOOKMARK:
|
if tag == TAG_BOOKMARK:
|
||||||
continue
|
continue
|
||||||
# skip grmed entries
|
# skip grmed entries
|
||||||
if (max(mid, 0), rid) in gstate.grm:
|
if (max(mbid-max(mw-1, 0), 0), rid) in gstate.grm:
|
||||||
continue
|
continue
|
||||||
dir.append((name, mid, mdir, rid, tag, w))
|
dir.append((name, mbid, mw, mdir, rid, tag, w))
|
||||||
|
|
||||||
# if we're root, append any orphaned bookmark entries so they
|
# if we're root, append any orphaned bookmark entries so they
|
||||||
# get reported
|
# get reported
|
||||||
if did == 0:
|
if did == 0:
|
||||||
for did, name, mid, mdir, rid, tag, w in bookmark_dids:
|
for did, name, mbid, mw, mdir, rid, tag, w in bookmark_dids:
|
||||||
if did in grmed_dir_dids:
|
if did in grmed_dir_dids:
|
||||||
continue
|
continue
|
||||||
# skip grmed entries
|
# skip grmed entries
|
||||||
if (not args.get('all')
|
if (not args.get('all')
|
||||||
and (max(mid, 0), rid) in gstate.grm):
|
and (max(mbid-max(mw-1, 0), 0), rid)
|
||||||
|
in gstate.grm):
|
||||||
continue
|
continue
|
||||||
dir.append((name, mid, mdir, rid, tag, w))
|
dir.append((name, mbid, mw, mdir, rid, tag, w))
|
||||||
|
|
||||||
for i, (name, mid, mdir, rid, tag, w) in enumerate(dir):
|
for i, (name, mbid, mw, mdir, rid, tag, w) in enumerate(dir):
|
||||||
# some special situations worth reporting
|
# some special situations worth reporting
|
||||||
notes = []
|
notes = []
|
||||||
grmed = (max(mid, 0), rid) in gstate.grm
|
grmed = (max(mbid-max(mw-1, 0), 0), rid) in gstate.grm
|
||||||
# grmed?
|
# grmed?
|
||||||
if grmed:
|
if grmed:
|
||||||
notes.append('grmed')
|
notes.append('grmed')
|
||||||
@@ -1120,9 +1134,10 @@ def main(disk, mroots=None, *,
|
|||||||
'{%s}:' % ','.join('%04x' % block
|
'{%s}:' % ','.join('%04x' % block
|
||||||
for block in it.chain([mdir.block],
|
for block in it.chain([mdir.block],
|
||||||
mdir.redund_blocks))
|
mdir.redund_blocks))
|
||||||
if mid != pmid else '',
|
if mbid != pmbid else '',
|
||||||
w_width, '%d.%d-%d' % (mid, rid-(w-1), rid)
|
w_width, '%d.%d-%d' % (
|
||||||
if w > 1 else '%d.%d' % (mid, rid)
|
mbid-max(mw-1, 0), rid-(w-1), rid)
|
||||||
|
if w > 1 else '%d.%d' % (mbid-max(mw-1, 0), rid)
|
||||||
if w > 0 else '',
|
if w > 0 else '',
|
||||||
f_width, '%s%s' % (
|
f_width, '%s%s' % (
|
||||||
prefixes[0+(i==len(dir)-1)],
|
prefixes[0+(i==len(dir)-1)],
|
||||||
@@ -1135,7 +1150,7 @@ def main(disk, mroots=None, *,
|
|||||||
if notes else '',
|
if notes else '',
|
||||||
'\x1b[m' if color and (grmed or tag == TAG_BOOKMARK)
|
'\x1b[m' if color and (grmed or tag == TAG_BOOKMARK)
|
||||||
else ''))
|
else ''))
|
||||||
pmid = mid
|
pmbid = mbid
|
||||||
|
|
||||||
# print attrs associated with this file?
|
# print attrs associated with this file?
|
||||||
if args.get('attrs'):
|
if args.get('attrs'):
|
||||||
|
|||||||
@@ -812,10 +812,10 @@ def main(disk, mroots=None, *,
|
|||||||
mweight = w
|
mweight = w
|
||||||
|
|
||||||
# traverse entries
|
# traverse entries
|
||||||
mid = -1
|
mbid = -1
|
||||||
while True:
|
while True:
|
||||||
done, mid, w, rbyd, rid, tags, path = mtree.btree_lookup(
|
done, mbid, mw, rbyd, rid, tags, path = mtree.btree_lookup(
|
||||||
f, block_size, mid+1,
|
f, block_size, mbid+1,
|
||||||
depth=args.get('depth', mdepth)-mdepth)
|
depth=args.get('depth', mdepth)-mdepth)
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
@@ -962,10 +962,10 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# find the max depth of each mdir to nicely align trees
|
# find the max depth of each mdir to nicely align trees
|
||||||
mdepth_ = 0
|
mdepth_ = 0
|
||||||
mid = -1
|
mbid = -1
|
||||||
while True:
|
while True:
|
||||||
done, mid, w, rbyd, rid, tags, path = mtree.btree_lookup(
|
done, mbid, mw, rbyd, rid, tags, path = mtree.btree_lookup(
|
||||||
f, block_size, mid+1,
|
f, block_size, mbid+1,
|
||||||
depth=args.get('depth', mdepth)-mdepth)
|
depth=args.get('depth', mdepth)-mdepth)
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
@@ -992,10 +992,10 @@ def main(disk, mroots=None, *,
|
|||||||
mdepth_ = max(mdepth_, rdepth)
|
mdepth_ = max(mdepth_, rdepth)
|
||||||
|
|
||||||
# compute the rbyd-tree for each mdir
|
# compute the rbyd-tree for each mdir
|
||||||
mid = -1
|
mbid = -1
|
||||||
while True:
|
while True:
|
||||||
done, mid, w, rbyd, rid, tags, path = mtree.btree_lookup(
|
done, mbid, mw, rbyd, rid, tags, path = mtree.btree_lookup(
|
||||||
f, block_size, mid+1,
|
f, block_size, mbid+1,
|
||||||
depth=args.get('depth', mdepth)-mdepth)
|
depth=args.get('depth', mdepth)-mdepth)
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
@@ -1023,7 +1023,7 @@ def main(disk, mroots=None, *,
|
|||||||
# connect the root to the mtree
|
# connect the root to the mtree
|
||||||
branch = max(
|
branch = max(
|
||||||
(branch for branch in tree
|
(branch for branch in tree
|
||||||
if branch.b[0] == mid-(w-1)),
|
if branch.b[0] == mbid-(mw-1)),
|
||||||
key=lambda branch: branch.d,
|
key=lambda branch: branch.d,
|
||||||
default=None)
|
default=None)
|
||||||
if branch:
|
if branch:
|
||||||
@@ -1037,7 +1037,7 @@ def main(disk, mroots=None, *,
|
|||||||
mdir_.lookup(-1, 0x1))
|
mdir_.lookup(-1, 0x1))
|
||||||
tree.add(TBranch(
|
tree.add(TBranch(
|
||||||
a=branch.b,
|
a=branch.b,
|
||||||
b=(mid-(w-1), len(path), 0, r_rid, r_tag),
|
b=(mbid-(mw-1), len(path), 0, r_rid, r_tag),
|
||||||
d=d_ + tdepth,
|
d=d_ + tdepth,
|
||||||
c='b',
|
c='b',
|
||||||
))
|
))
|
||||||
@@ -1047,8 +1047,8 @@ def main(disk, mroots=None, *,
|
|||||||
a_rid, a_tag = branch.a
|
a_rid, a_tag = branch.a
|
||||||
b_rid, b_tag = branch.b
|
b_rid, b_tag = branch.b
|
||||||
tree.add(TBranch(
|
tree.add(TBranch(
|
||||||
a=(mid-(w-1), len(path), 0, a_rid, a_tag),
|
a=(mbid-(mw-1), len(path), 0, a_rid, a_tag),
|
||||||
b=(mid-(w-1), len(path), 0, b_rid, b_tag),
|
b=(mbid-(mw-1), len(path), 0, b_rid, b_tag),
|
||||||
d=(d_ + tdepth + 1
|
d=(d_ + tdepth + 1
|
||||||
+ branch.d + mdepth_-rdepth),
|
+ branch.d + mdepth_-rdepth),
|
||||||
c=branch.c,
|
c=branch.c,
|
||||||
@@ -1181,11 +1181,11 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# remap branches to leaves if we aren't showing inner branches
|
# remap branches to leaves if we aren't showing inner branches
|
||||||
if not args.get('inner'):
|
if not args.get('inner'):
|
||||||
mid = -1
|
mbid = -1
|
||||||
while True:
|
while True:
|
||||||
done, mid, w, rbyd, rid, tags, path = (
|
done, mbid, mw, rbyd, rid, tags, path = (
|
||||||
mtree.btree_lookup(
|
mtree.btree_lookup(
|
||||||
f, block_size, mid+1,
|
f, block_size, mbid+1,
|
||||||
depth=args.get('depth', mdepth)-mdepth))
|
depth=args.get('depth', mdepth)-mdepth))
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
@@ -1215,7 +1215,7 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
tree_ = set()
|
tree_ = set()
|
||||||
for branch in tree:
|
for branch in tree:
|
||||||
if branch.a[0] == mid-(w-1):
|
if branch.a[0] == mbid-(mw-1):
|
||||||
a_bid, a_bd, _, _, _ = branch.a
|
a_bid, a_bd, _, _, _ = branch.a
|
||||||
branch = TBranch(
|
branch = TBranch(
|
||||||
a=(a_bid, a_bd+1, 0, rid, tag),
|
a=(a_bid, a_bd+1, 0, rid, tag),
|
||||||
@@ -1223,7 +1223,7 @@ def main(disk, mroots=None, *,
|
|||||||
d=branch.d,
|
d=branch.d,
|
||||||
c=branch.c,
|
c=branch.c,
|
||||||
)
|
)
|
||||||
if branch.b[0] == mid-(w-1):
|
if branch.b[0] == mbid-(mw-1):
|
||||||
b_bid, b_bd, _, _, _ = branch.b
|
b_bid, b_bd, _, _, _ = branch.b
|
||||||
branch = TBranch(
|
branch = TBranch(
|
||||||
a=branch.a,
|
a=branch.a,
|
||||||
@@ -1241,7 +1241,7 @@ def main(disk, mroots=None, *,
|
|||||||
if t_depth > 0:
|
if t_depth > 0:
|
||||||
t_width = 2*t_depth + 2
|
t_width = 2*t_depth + 2
|
||||||
|
|
||||||
def treerepr(mid, w, md, mrid, rid, tag):
|
def treerepr(mbid, mw, md, mrid, rid, tag):
|
||||||
if t_depth == 0:
|
if t_depth == 0:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@@ -1276,7 +1276,7 @@ def main(disk, mroots=None, *,
|
|||||||
was = None
|
was = None
|
||||||
for d in range(t_depth):
|
for d in range(t_depth):
|
||||||
t, c, was = branchrepr(
|
t, c, was = branchrepr(
|
||||||
(mid-max(w-1, 0), md, mrid-max(w-1, 0), rid, tag),
|
(mbid-max(mw-1, 0), md, mrid-max(mw-1, 0), rid, tag),
|
||||||
d, was)
|
d, was)
|
||||||
|
|
||||||
trunk.append('%s%s%s%s' % (
|
trunk.append('%s%s%s%s' % (
|
||||||
@@ -1291,7 +1291,7 @@ def main(disk, mroots=None, *,
|
|||||||
return '%s ' % ''.join(trunk)
|
return '%s ' % ''.join(trunk)
|
||||||
|
|
||||||
|
|
||||||
def dbg_mdir(mdir, mid, md):
|
def dbg_mdir(mdir, mbid, mw, md):
|
||||||
for i, (rid, tag, w, j, d, data) in enumerate(mdir):
|
for i, (rid, tag, w, j, d, data) in enumerate(mdir):
|
||||||
# show human-readable tag representation
|
# show human-readable tag representation
|
||||||
print('%12s %s%-57s' % (
|
print('%12s %s%-57s' % (
|
||||||
@@ -1299,11 +1299,12 @@ def main(disk, mroots=None, *,
|
|||||||
for block in it.chain([mdir.block],
|
for block in it.chain([mdir.block],
|
||||||
mdir.redund_blocks))
|
mdir.redund_blocks))
|
||||||
if i == 0 else '',
|
if i == 0 else '',
|
||||||
treerepr(mid, 1, md, 0, rid, tag)
|
treerepr(mbid-max(mw-1, 0), 0, md, 0, rid, tag)
|
||||||
if args.get('tree') or args.get('btree') else '',
|
if args.get('tree') or args.get('btree') else '',
|
||||||
'%*s %-22s%s' % (
|
'%*s %-22s%s' % (
|
||||||
w_width, '%d.%d-%d' % (mid, rid-(w-1), rid)
|
w_width, '%d.%d-%d' % (
|
||||||
if w > 1 else '%d.%d' % (mid, rid)
|
mbid-max(mw-1, 0), rid-(w-1), rid)
|
||||||
|
if w > 1 else '%d.%d' % (mbid-max(mw-1, 0), rid)
|
||||||
if w > 0 or i == 0 else '',
|
if w > 0 or i == 0 else '',
|
||||||
tagrepr(tag, w, len(data), j),
|
tagrepr(tag, w, len(data), j),
|
||||||
' %s' % next(xxd(data, 8), '')
|
' %s' % next(xxd(data, 8), '')
|
||||||
@@ -1410,7 +1411,7 @@ def main(disk, mroots=None, *,
|
|||||||
print('%-11s %*s%-*s %-22s %s' % (
|
print('%-11s %*s%-*s %-22s %s' % (
|
||||||
'mdir',
|
'mdir',
|
||||||
t_width, '',
|
t_width, '',
|
||||||
w_width, 'ids',
|
w_width, 'mid',
|
||||||
'tag',
|
'tag',
|
||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
@@ -1435,7 +1436,7 @@ def main(disk, mroots=None, *,
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# show the mdir
|
# show the mdir
|
||||||
dbg_mdir(mroot, -1, d)
|
dbg_mdir(mroot, -1, 0, d)
|
||||||
|
|
||||||
# stop here?
|
# stop here?
|
||||||
if args.get('depth') and mdepth >= args.get('depth'):
|
if args.get('depth') and mdepth >= args.get('depth'):
|
||||||
@@ -1469,7 +1470,7 @@ def main(disk, mroots=None, *,
|
|||||||
corrupted = True
|
corrupted = True
|
||||||
else:
|
else:
|
||||||
# show the mdir
|
# show the mdir
|
||||||
dbg_mdir(mdir, 0, 0)
|
dbg_mdir(mdir, 0, 0, 0)
|
||||||
|
|
||||||
# fetch the actual mtree, if there is one
|
# fetch the actual mtree, if there is one
|
||||||
if not args.get('depth') or mdepth < args.get('depth'):
|
if not args.get('depth') or mdepth < args.get('depth'):
|
||||||
@@ -1479,10 +1480,10 @@ def main(disk, mroots=None, *,
|
|||||||
mtree = Rbyd.fetch(f, block_size, block, trunk)
|
mtree = Rbyd.fetch(f, block_size, block, trunk)
|
||||||
|
|
||||||
# traverse entries
|
# traverse entries
|
||||||
mid = -1
|
mbid = -1
|
||||||
while True:
|
while True:
|
||||||
done, mid, w, rbyd, rid, tags, path = mtree.btree_lookup(
|
done, mbid, mw, rbyd, rid, tags, path = mtree.btree_lookup(
|
||||||
f, block_size, mid+1,
|
f, block_size, mbid+1,
|
||||||
depth=args.get('depth', mdepth)-mdepth)
|
depth=args.get('depth', mdepth)-mdepth)
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
@@ -1544,7 +1545,7 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# print btree entries in certain cases
|
# print btree entries in certain cases
|
||||||
if args.get('inner') or not mdir__:
|
if args.get('inner') or not mdir__:
|
||||||
dbg_branch(mid, w, rbyd, rid, tags, len(path)-1)
|
dbg_branch(mbid, mw, rbyd, rid, tags, len(path)-1)
|
||||||
|
|
||||||
if not mdir__:
|
if not mdir__:
|
||||||
continue
|
continue
|
||||||
@@ -1567,7 +1568,7 @@ def main(disk, mroots=None, *,
|
|||||||
corrupted = True
|
corrupted = True
|
||||||
else:
|
else:
|
||||||
# show the mdir
|
# show the mdir
|
||||||
dbg_mdir(mdir_, mid, len(path))
|
dbg_mdir(mdir_, mbid, mw, len(path))
|
||||||
|
|
||||||
# force next btree entry to be shown
|
# force next btree entry to be shown
|
||||||
prbyd = None
|
prbyd = None
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ def dbg_log(data, block_size, rev, off, weight, *,
|
|||||||
print('%-8s %*s%-*s %-22s %s' % (
|
print('%-8s %*s%-*s %-22s %s' % (
|
||||||
'off',
|
'off',
|
||||||
lifetime_width, '',
|
lifetime_width, '',
|
||||||
w_width, 'ids',
|
w_width, 'rid',
|
||||||
'tag',
|
'tag',
|
||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
@@ -750,7 +750,7 @@ def dbg_tree(data, block_size, rev, trunk, weight, *,
|
|||||||
print('%-8s %*s%-*s %-22s %s' % (
|
print('%-8s %*s%-*s %-22s %s' % (
|
||||||
'off',
|
'off',
|
||||||
t_width, '',
|
t_width, '',
|
||||||
w_width, 'ids',
|
w_width, 'rid',
|
||||||
'tag',
|
'tag',
|
||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|||||||
@@ -3485,8 +3485,9 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
|
|
||||||
@@ -3494,8 +3495,9 @@ code = '''
|
|||||||
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -3504,8 +3506,9 @@ code = '''
|
|||||||
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -3606,8 +3609,9 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
|
|
||||||
@@ -3615,8 +3619,9 @@ code = '''
|
|||||||
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -3625,8 +3630,9 @@ code = '''
|
|||||||
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -3738,8 +3744,9 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
|
|
||||||
@@ -3747,8 +3754,9 @@ code = '''
|
|||||||
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -3757,8 +3765,9 @@ code = '''
|
|||||||
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -3862,8 +3871,9 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
|
|
||||||
@@ -3871,8 +3881,9 @@ code = '''
|
|||||||
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -3881,8 +3892,9 @@ code = '''
|
|||||||
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -3997,8 +4009,9 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
|
|
||||||
@@ -4006,8 +4019,9 @@ code = '''
|
|||||||
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -4016,8 +4030,9 @@ code = '''
|
|||||||
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -4164,8 +4179,9 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
|
|
||||||
@@ -4173,8 +4189,9 @@ code = '''
|
|||||||
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
seen[branch->block / 8] |= 1 << (branch->block % 8);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
|
|
||||||
@@ -4183,8 +4200,9 @@ code = '''
|
|||||||
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
seen[mdir->u.m.blocks[0] / 8] |= 1 << (mdir->u.m.blocks[0] % 8);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
@@ -4270,20 +4288,23 @@ code = '''
|
|||||||
|
|
||||||
if (tag_ == LFSR_TAG_BTREE) {
|
if (tag_ == LFSR_TAG_BTREE) {
|
||||||
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
lfsr_rbyd_t *branch = (lfsr_rbyd_t *)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
printf("traversal: %d.%d 0x%x btree 0x%x.%x\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
branch->block, branch->trunk);
|
branch->block, branch->trunk);
|
||||||
} else if (tag_ == LFSR_TAG_MDIR) {
|
} else if (tag_ == LFSR_TAG_MDIR) {
|
||||||
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data_.u.b.buffer;
|
||||||
printf("traversal: %d 0x%x mdir 0x{%x,%x}\n",
|
printf("traversal: %d.%d 0x%x mdir 0x{%x,%x}\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
|
||||||
} else {
|
} else {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
printf("traversal: %d 0x%x %d\n",
|
printf("traversal: %d.%d 0x%x %d\n",
|
||||||
mid_,
|
mid_ & lfsr_mbidmask(&lfs),
|
||||||
|
mid_ & lfsr_mridmask(&lfs),
|
||||||
tag_,
|
tag_,
|
||||||
lfsr_data_size(&data_));
|
lfsr_data_size(&data_));
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user