scripts: Dropped list/tuple distinction in Rbyd.fetch
Also tweaked how we fetch shrubs, adding Rbyd.fetchshrub and Btree.fetchshrub instead of overloading the bd argument. Oh, and also added --trunk to dbgmtree.py and dbglfs.py. Actually _using_ --trunk isn't advised, since it will probably just result in a corrupted filesystem, but these scripts are for accessing things that aren't normally allowed anyways. The reason for dropping the list/tuple distinction is because it was a big ugly hack, unpythonic, and likely to catch users (and myself) by surprise. Now, Rbyd.fetch and friends always require separate block/trunk arguments, and the exercise of deciding which trunk to use is left up to the caller.
This commit is contained in:
+5
-5
@@ -32,10 +32,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -66,7 +66,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def xxd(data, width=16):
|
def xxd(data, width=16):
|
||||||
for i in range(0, len(data), width):
|
for i in range(0, len(data), width):
|
||||||
|
|||||||
+5
-5
@@ -97,10 +97,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -131,7 +131,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def crc32c(data, crc=0):
|
def crc32c(data, crc=0):
|
||||||
crc ^= 0xffffffff
|
crc ^= 0xffffffff
|
||||||
|
|||||||
+79
-82
@@ -80,10 +80,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -114,7 +114,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def crc32c(data, crc=0):
|
def crc32c(data, crc=0):
|
||||||
crc ^= 0xffffffff
|
crc ^= 0xffffffff
|
||||||
@@ -456,9 +456,9 @@ class Rattr:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.data = data
|
self.data = data
|
||||||
@@ -532,9 +532,9 @@ class Ralt:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.jump = jump
|
self.jump = jump
|
||||||
@@ -587,9 +587,9 @@ class Rbyd:
|
|||||||
gcksumdelta=None,
|
gcksumdelta=None,
|
||||||
corrupt=False):
|
corrupt=False):
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.trunk = trunk
|
self.trunk = trunk
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
self.rev = rev
|
self.rev = rev
|
||||||
@@ -632,51 +632,7 @@ class Rbyd:
|
|||||||
return hash((frozenset(self.blocks), self.trunk))
|
return hash((frozenset(self.blocks), self.trunk))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def _fetch(cls, data, block, trunk=None):
|
||||||
# multiple blocks? unfortunately this must be a list
|
|
||||||
if isinstance(blocks, list):
|
|
||||||
# fetch all blocks
|
|
||||||
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
|
||||||
# determine most recent revision
|
|
||||||
i = 0
|
|
||||||
for i_, rbyd in enumerate(rbyds):
|
|
||||||
# compare with sequence arithmetic
|
|
||||||
if rbyd and (
|
|
||||||
not rbyds[i]
|
|
||||||
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
|
||||||
or (rbyd.rev == rbyds[i].rev
|
|
||||||
and rbyd.trunk > rbyds[i].trunk)):
|
|
||||||
i = i_
|
|
||||||
# keep track of the other blocks
|
|
||||||
rbyd = rbyds[i]
|
|
||||||
rbyd.blocks += tuple(
|
|
||||||
rbyds[(i+1+j) % len(rbyds)].block
|
|
||||||
for j in range(len(rbyds)-1))
|
|
||||||
# and patch the gcksumdelta if we have one
|
|
||||||
if rbyd.gcksumdelta is not None:
|
|
||||||
rbyd.gcksumdelta.blocks = rbyd.blocks
|
|
||||||
return rbyd
|
|
||||||
|
|
||||||
block = blocks
|
|
||||||
|
|
||||||
# blocks may also encode trunks
|
|
||||||
block, trunk = (
|
|
||||||
block[0] if isinstance(block, tuple)
|
|
||||||
else block,
|
|
||||||
trunk if trunk is not None
|
|
||||||
else block[1] if isinstance(block, tuple)
|
|
||||||
else None)
|
|
||||||
|
|
||||||
# bd can be either a bd reference or a preread block
|
|
||||||
#
|
|
||||||
# preread blocks can be useful for avoiding race conditions
|
|
||||||
# with cksums and shrubs
|
|
||||||
if isinstance(bd, Bd):
|
|
||||||
# seek/read the block
|
|
||||||
data = bd.readblock(block)
|
|
||||||
else:
|
|
||||||
data = bd
|
|
||||||
|
|
||||||
# fetch the rbyd
|
# fetch the rbyd
|
||||||
rev = fromle32(data[0:4])
|
rev = fromle32(data[0:4])
|
||||||
cksum = 0
|
cksum = 0
|
||||||
@@ -773,6 +729,39 @@ class Rbyd:
|
|||||||
gcksumdelta=gcksumdelta,
|
gcksumdelta=gcksumdelta,
|
||||||
corrupt=not trunk_)
|
corrupt=not trunk_)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
|
# multiple blocks?
|
||||||
|
if not isinstance(blocks, int):
|
||||||
|
# fetch all blocks
|
||||||
|
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
||||||
|
# determine most recent revision
|
||||||
|
i = 0
|
||||||
|
for i_, rbyd in enumerate(rbyds):
|
||||||
|
# compare with sequence arithmetic
|
||||||
|
if rbyd and (
|
||||||
|
not rbyds[i]
|
||||||
|
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
||||||
|
or (rbyd.rev == rbyds[i].rev
|
||||||
|
and rbyd.trunk > rbyds[i].trunk)):
|
||||||
|
i = i_
|
||||||
|
# keep track of the other blocks
|
||||||
|
rbyd = rbyds[i]
|
||||||
|
rbyd.blocks += tuple(
|
||||||
|
rbyds[(i+1+j) % len(rbyds)].block
|
||||||
|
for j in range(len(rbyds)-1))
|
||||||
|
# and patch the gcksumdelta if we have one
|
||||||
|
if rbyd.gcksumdelta is not None:
|
||||||
|
rbyd.gcksumdelta.blocks = rbyd.blocks
|
||||||
|
return rbyd
|
||||||
|
|
||||||
|
# seek/read the block
|
||||||
|
block = blocks
|
||||||
|
data = bd.readblock(block)
|
||||||
|
|
||||||
|
# fetch the rbyd
|
||||||
|
return cls._fetch(data, block, trunk)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# try to fetch the rbyd normally
|
# try to fetch the rbyd normally
|
||||||
@@ -789,6 +778,15 @@ class Rbyd:
|
|||||||
|
|
||||||
return rbyd
|
return rbyd
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, rbyd, trunk):
|
||||||
|
# steal the original rbyd's data
|
||||||
|
#
|
||||||
|
# this helps avoid race conditions with cksums and stuff
|
||||||
|
shrub = cls._fetch(rbyd.data, rbyd.block, trunk)
|
||||||
|
shrub.blocks = rbyd.blocks
|
||||||
|
return shrub
|
||||||
|
|
||||||
def lookupnext(self, rid, tag=None, *,
|
def lookupnext(self, rid, tag=None, *,
|
||||||
path=False):
|
path=False):
|
||||||
if not self or rid >= self.weight:
|
if not self or rid >= self.weight:
|
||||||
@@ -1157,32 +1155,21 @@ class Btree:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
# bd can either be a bd reference or a tuple of bd + data to
|
|
||||||
# avoid rereads, but we need a real bd reference somehow
|
|
||||||
if isinstance(bd, tuple):
|
|
||||||
bd, data = bd
|
|
||||||
else:
|
|
||||||
bd, data = bd, bd
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# rbyd fetch does most of the work here
|
# rbyd fetch does most of the work here
|
||||||
rbyd = Rbyd.fetch(data, blocks, trunk)
|
rbyd = Rbyd.fetch(bd, blocks, trunk)
|
||||||
return cls(bd, rbyd)
|
return cls(bd, rbyd)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# bd can either be a bd reference or a tuple of bd + data to
|
|
||||||
# avoid rereads, but we need a real bd reference somehow
|
|
||||||
if isinstance(bd, tuple):
|
|
||||||
bd, data = bd
|
|
||||||
else:
|
|
||||||
bd, data = bd, bd
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# rbyd fetchck does most of the work here
|
# rbyd fetchck does most of the work here
|
||||||
rbyd = Rbyd.fetchck(data, blocks, trunk, weight, cksum)
|
rbyd = Rbyd.fetchck(bd, blocks, trunk, weight, cksum)
|
||||||
return cls(bd, rbyd)
|
return cls(bd, rbyd)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, bd, rbyd, trunk):
|
||||||
|
shrub = Rbyd.fetchshrub(rbyd, trunk)
|
||||||
|
return cls(bd, shrub)
|
||||||
|
|
||||||
def lookupleaf(self, bid, *,
|
def lookupleaf(self, bid, *,
|
||||||
path=None,
|
path=None,
|
||||||
depth=None):
|
depth=None):
|
||||||
@@ -1589,9 +1576,9 @@ class Btree:
|
|||||||
|
|
||||||
|
|
||||||
def main(disk, roots=None, *,
|
def main(disk, roots=None, *,
|
||||||
|
trunk=None,
|
||||||
block_size=None,
|
block_size=None,
|
||||||
block_count=None,
|
block_count=None,
|
||||||
trunk=None,
|
|
||||||
color='auto',
|
color='auto',
|
||||||
**args):
|
**args):
|
||||||
# figure out what color should be
|
# figure out what color should be
|
||||||
@@ -1609,9 +1596,19 @@ def main(disk, roots=None, *,
|
|||||||
block_count = block_count_
|
block_count = block_count_
|
||||||
|
|
||||||
# flatten roots, default to block 0
|
# flatten roots, default to block 0
|
||||||
if not roots:
|
roots = list(it.chain.from_iterable(roots)) if roots else [0]
|
||||||
roots = [(0,)]
|
|
||||||
roots = [block for roots_ in roots for block in roots_]
|
# roots may also encode trunks
|
||||||
|
roots, trunk = (
|
||||||
|
[block[0] if isinstance(block, tuple)
|
||||||
|
else block
|
||||||
|
for block in roots],
|
||||||
|
trunk if trunk is not None
|
||||||
|
else ft.reduce(
|
||||||
|
lambda x, y: y,
|
||||||
|
(block[1] for block in roots
|
||||||
|
if isinstance(block, tuple)),
|
||||||
|
None))
|
||||||
|
|
||||||
# we seek around a bunch, so just keep the disk open
|
# we seek around a bunch, so just keep the disk open
|
||||||
with open(disk, 'rb') as f:
|
with open(disk, 'rb') as f:
|
||||||
@@ -1739,6 +1736,10 @@ if __name__ == "__main__":
|
|||||||
nargs='*',
|
nargs='*',
|
||||||
type=rbydaddr,
|
type=rbydaddr,
|
||||||
help="Block address of the roots of the tree.")
|
help="Block address of the roots of the tree.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--trunk',
|
||||||
|
type=lambda x: int(x, 0),
|
||||||
|
help="Use this offset as the trunk of the tree.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-b', '--block-size',
|
'-b', '--block-size',
|
||||||
type=bdgeom,
|
type=bdgeom,
|
||||||
@@ -1747,10 +1748,6 @@ if __name__ == "__main__":
|
|||||||
'--block-count',
|
'--block-count',
|
||||||
type=lambda x: int(x, 0),
|
type=lambda x: int(x, 0),
|
||||||
help="Block count in blocks.")
|
help="Block count in blocks.")
|
||||||
parser.add_argument(
|
|
||||||
'--trunk',
|
|
||||||
type=lambda x: int(x, 0),
|
|
||||||
help="Use this offset as the trunk of the tree.")
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--color',
|
'--color',
|
||||||
choices=['never', 'always', 'auto'],
|
choices=['never', 'always', 'auto'],
|
||||||
|
|||||||
+5
-5
@@ -32,10 +32,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -66,7 +66,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def xxd(data, width=16):
|
def xxd(data, width=16):
|
||||||
for i in range(0, len(data), width):
|
for i in range(0, len(data), width):
|
||||||
|
|||||||
+93
-104
@@ -81,10 +81,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -115,7 +115,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def crc32c(data, crc=0):
|
def crc32c(data, crc=0):
|
||||||
crc ^= 0xffffffff
|
crc ^= 0xffffffff
|
||||||
@@ -505,9 +505,9 @@ class Rattr:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.data = data
|
self.data = data
|
||||||
@@ -581,9 +581,9 @@ class Ralt:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.jump = jump
|
self.jump = jump
|
||||||
@@ -636,9 +636,9 @@ class Rbyd:
|
|||||||
gcksumdelta=None,
|
gcksumdelta=None,
|
||||||
corrupt=False):
|
corrupt=False):
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.trunk = trunk
|
self.trunk = trunk
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
self.rev = rev
|
self.rev = rev
|
||||||
@@ -681,51 +681,7 @@ class Rbyd:
|
|||||||
return hash((frozenset(self.blocks), self.trunk))
|
return hash((frozenset(self.blocks), self.trunk))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def _fetch(cls, data, block, trunk=None):
|
||||||
# multiple blocks? unfortunately this must be a list
|
|
||||||
if isinstance(blocks, list):
|
|
||||||
# fetch all blocks
|
|
||||||
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
|
||||||
# determine most recent revision
|
|
||||||
i = 0
|
|
||||||
for i_, rbyd in enumerate(rbyds):
|
|
||||||
# compare with sequence arithmetic
|
|
||||||
if rbyd and (
|
|
||||||
not rbyds[i]
|
|
||||||
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
|
||||||
or (rbyd.rev == rbyds[i].rev
|
|
||||||
and rbyd.trunk > rbyds[i].trunk)):
|
|
||||||
i = i_
|
|
||||||
# keep track of the other blocks
|
|
||||||
rbyd = rbyds[i]
|
|
||||||
rbyd.blocks += tuple(
|
|
||||||
rbyds[(i+1+j) % len(rbyds)].block
|
|
||||||
for j in range(len(rbyds)-1))
|
|
||||||
# and patch the gcksumdelta if we have one
|
|
||||||
if rbyd.gcksumdelta is not None:
|
|
||||||
rbyd.gcksumdelta.blocks = rbyd.blocks
|
|
||||||
return rbyd
|
|
||||||
|
|
||||||
block = blocks
|
|
||||||
|
|
||||||
# blocks may also encode trunks
|
|
||||||
block, trunk = (
|
|
||||||
block[0] if isinstance(block, tuple)
|
|
||||||
else block,
|
|
||||||
trunk if trunk is not None
|
|
||||||
else block[1] if isinstance(block, tuple)
|
|
||||||
else None)
|
|
||||||
|
|
||||||
# bd can be either a bd reference or a preread block
|
|
||||||
#
|
|
||||||
# preread blocks can be useful for avoiding race conditions
|
|
||||||
# with cksums and shrubs
|
|
||||||
if isinstance(bd, Bd):
|
|
||||||
# seek/read the block
|
|
||||||
data = bd.readblock(block)
|
|
||||||
else:
|
|
||||||
data = bd
|
|
||||||
|
|
||||||
# fetch the rbyd
|
# fetch the rbyd
|
||||||
rev = fromle32(data[0:4])
|
rev = fromle32(data[0:4])
|
||||||
cksum = 0
|
cksum = 0
|
||||||
@@ -822,6 +778,39 @@ class Rbyd:
|
|||||||
gcksumdelta=gcksumdelta,
|
gcksumdelta=gcksumdelta,
|
||||||
corrupt=not trunk_)
|
corrupt=not trunk_)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
|
# multiple blocks?
|
||||||
|
if not isinstance(blocks, int):
|
||||||
|
# fetch all blocks
|
||||||
|
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
||||||
|
# determine most recent revision
|
||||||
|
i = 0
|
||||||
|
for i_, rbyd in enumerate(rbyds):
|
||||||
|
# compare with sequence arithmetic
|
||||||
|
if rbyd and (
|
||||||
|
not rbyds[i]
|
||||||
|
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
||||||
|
or (rbyd.rev == rbyds[i].rev
|
||||||
|
and rbyd.trunk > rbyds[i].trunk)):
|
||||||
|
i = i_
|
||||||
|
# keep track of the other blocks
|
||||||
|
rbyd = rbyds[i]
|
||||||
|
rbyd.blocks += tuple(
|
||||||
|
rbyds[(i+1+j) % len(rbyds)].block
|
||||||
|
for j in range(len(rbyds)-1))
|
||||||
|
# and patch the gcksumdelta if we have one
|
||||||
|
if rbyd.gcksumdelta is not None:
|
||||||
|
rbyd.gcksumdelta.blocks = rbyd.blocks
|
||||||
|
return rbyd
|
||||||
|
|
||||||
|
# seek/read the block
|
||||||
|
block = blocks
|
||||||
|
data = bd.readblock(block)
|
||||||
|
|
||||||
|
# fetch the rbyd
|
||||||
|
return cls._fetch(data, block, trunk)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# try to fetch the rbyd normally
|
# try to fetch the rbyd normally
|
||||||
@@ -838,6 +827,15 @@ class Rbyd:
|
|||||||
|
|
||||||
return rbyd
|
return rbyd
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, rbyd, trunk):
|
||||||
|
# steal the original rbyd's data
|
||||||
|
#
|
||||||
|
# this helps avoid race conditions with cksums and stuff
|
||||||
|
shrub = cls._fetch(rbyd.data, rbyd.block, trunk)
|
||||||
|
shrub.blocks = rbyd.blocks
|
||||||
|
return shrub
|
||||||
|
|
||||||
def lookupnext(self, rid, tag=None, *,
|
def lookupnext(self, rid, tag=None, *,
|
||||||
path=False):
|
path=False):
|
||||||
if not self or rid >= self.weight:
|
if not self or rid >= self.weight:
|
||||||
@@ -1206,32 +1204,21 @@ class Btree:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
# bd can either be a bd reference or a tuple of bd + data to
|
|
||||||
# avoid rereads, but we need a real bd reference somehow
|
|
||||||
if isinstance(bd, tuple):
|
|
||||||
bd, data = bd
|
|
||||||
else:
|
|
||||||
bd, data = bd, bd
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# rbyd fetch does most of the work here
|
# rbyd fetch does most of the work here
|
||||||
rbyd = Rbyd.fetch(data, blocks, trunk)
|
rbyd = Rbyd.fetch(bd, blocks, trunk)
|
||||||
return cls(bd, rbyd)
|
return cls(bd, rbyd)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# bd can either be a bd reference or a tuple of bd + data to
|
|
||||||
# avoid rereads, but we need a real bd reference somehow
|
|
||||||
if isinstance(bd, tuple):
|
|
||||||
bd, data = bd
|
|
||||||
else:
|
|
||||||
bd, data = bd, bd
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# rbyd fetchck does most of the work here
|
# rbyd fetchck does most of the work here
|
||||||
rbyd = Rbyd.fetchck(data, blocks, trunk, weight, cksum)
|
rbyd = Rbyd.fetchck(bd, blocks, trunk, weight, cksum)
|
||||||
return cls(bd, rbyd)
|
return cls(bd, rbyd)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, bd, rbyd, trunk):
|
||||||
|
shrub = Rbyd.fetchshrub(rbyd, trunk)
|
||||||
|
return cls(bd, shrub)
|
||||||
|
|
||||||
def lookupleaf(self, bid, *,
|
def lookupleaf(self, bid, *,
|
||||||
path=None,
|
path=None,
|
||||||
depth=None):
|
depth=None):
|
||||||
@@ -1804,13 +1791,9 @@ class Mdir:
|
|||||||
return hash(frozenset(self.blocks))
|
return hash(frozenset(self.blocks))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, mid, blocks):
|
def fetch(cls, bd, mid, blocks, trunk=None):
|
||||||
rbyd = Rbyd.fetch(bd, blocks)
|
rbyd = Rbyd.fetch(bd, blocks, trunk)
|
||||||
# this affects mbits
|
return cls(mid, rbyd, mbits=Mtree.mbits_(bd))
|
||||||
if isinstance(bd, Bd):
|
|
||||||
return cls(mid, rbyd, mbits=Mtree.mbits_(bd))
|
|
||||||
else:
|
|
||||||
return cls(mid, rbyd)
|
|
||||||
|
|
||||||
def lookup_(self, mid, tag=None, mask=None, *,
|
def lookup_(self, mid, tag=None, mask=None, *,
|
||||||
path=False):
|
path=False):
|
||||||
@@ -1999,11 +1982,8 @@ class Mtree:
|
|||||||
return hash(self.mrootanchor)
|
return hash(self.mrootanchor)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks=None, *,
|
def fetch(cls, bd, blocks=None, trunk=None, *,
|
||||||
depth=None):
|
depth=None):
|
||||||
# we need a real bd reference here
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# default to blocks 0x{0,1}
|
# default to blocks 0x{0,1}
|
||||||
if blocks is None:
|
if blocks is None:
|
||||||
blocks = [0, 1]
|
blocks = [0, 1]
|
||||||
@@ -2012,7 +1992,7 @@ class Mtree:
|
|||||||
mbits = Mtree.mbits_(bd)
|
mbits = Mtree.mbits_(bd)
|
||||||
|
|
||||||
# fetch the mrootanchor
|
# fetch the mrootanchor
|
||||||
mrootanchor = Mdir.fetch(bd, -1, blocks)
|
mrootanchor = Mdir.fetch(bd, -1, blocks, trunk)
|
||||||
|
|
||||||
# follow the mroot chain to try to find the active mroot
|
# follow the mroot chain to try to find the active mroot
|
||||||
mroot = mrootanchor
|
mroot = mrootanchor
|
||||||
@@ -2736,15 +2716,10 @@ class Bptr:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, rattr, block, off, size, cksize, cksum):
|
def fetch(cls, bd, rattr, block, off, size, cksize, cksum):
|
||||||
# bd can be either a bd reference or a preread block
|
# seek/read cksize bytes from the block, the actual data should
|
||||||
if isinstance(bd, Bd):
|
# always be a subset of cksize
|
||||||
# seek/read cksize bytes from the block, the actual data
|
bd.seek(block)
|
||||||
# should always be a subset of this
|
ckdata = bd.read(cksize)
|
||||||
bd.seek(block)
|
|
||||||
ckdata = bd.read(cksize)
|
|
||||||
else:
|
|
||||||
# truncate to cksize
|
|
||||||
ckdata = bd[:cksize]
|
|
||||||
|
|
||||||
return cls(rattr, block, off, size, cksize, cksum, ckdata)
|
return cls(rattr, block, off, size, cksize, cksum, ckdata)
|
||||||
|
|
||||||
@@ -3303,10 +3278,10 @@ class Lfs:
|
|||||||
return hash(self.mrootanchor)
|
return hash(self.mrootanchor)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks=None, *,
|
def fetch(cls, bd, blocks=None, trunk=None, *,
|
||||||
depth=None):
|
depth=None):
|
||||||
# Mtree does most of the work here
|
# Mtree does most of the work here
|
||||||
mtree = Mtree.fetch(bd, blocks,
|
mtree = Mtree.fetch(bd, blocks, trunk,
|
||||||
depth=depth)
|
depth=depth)
|
||||||
return cls(bd, mtree)
|
return cls(bd, mtree)
|
||||||
|
|
||||||
@@ -3597,8 +3572,7 @@ class Lfs:
|
|||||||
if (self.struct is not None
|
if (self.struct is not None
|
||||||
and (self.struct.tag & ~0x3) == TAG_BSHRUB):
|
and (self.struct.tag & ~0x3) == TAG_BSHRUB):
|
||||||
weight, trunk = fromshrub(self.struct.data)
|
weight, trunk = fromshrub(self.struct.data)
|
||||||
self.bshrub = Btree.fetch(
|
self.bshrub = Btree.fetchshrub(lfs.bd, mdir.rbyd, trunk)
|
||||||
(lfs.bd, mdir.data), self.mdir.blocks, trunk)
|
|
||||||
elif (self.struct is not None
|
elif (self.struct is not None
|
||||||
and (self.struct.tag & ~0x3) == TAG_BTREE):
|
and (self.struct.tag & ~0x3) == TAG_BTREE):
|
||||||
weight, block, trunk, cksum = frombtree(self.struct.data)
|
weight, block, trunk, cksum = frombtree(self.struct.data)
|
||||||
@@ -4393,6 +4367,7 @@ def dbg_files(lfs, paths,
|
|||||||
|
|
||||||
|
|
||||||
def main(disk, mroots=None, paths=None, *,
|
def main(disk, mroots=None, paths=None, *,
|
||||||
|
trunk=None,
|
||||||
block_size=None,
|
block_size=None,
|
||||||
block_count=None,
|
block_count=None,
|
||||||
color='auto',
|
color='auto',
|
||||||
@@ -4426,9 +4401,19 @@ def main(disk, mroots=None, paths=None, *,
|
|||||||
block_count = block_count_
|
block_count = block_count_
|
||||||
|
|
||||||
# flatten mroots, default to 0x{0,1}
|
# flatten mroots, default to 0x{0,1}
|
||||||
if not mroots:
|
mroots = list(it.chain.from_iterable(mroots)) if mroots else [0, 1]
|
||||||
mroots = [(0,1)]
|
|
||||||
mroots = [block for mroots_ in mroots for block in mroots_]
|
# mroots may also encode trunks
|
||||||
|
mroots, trunk = (
|
||||||
|
[block[0] if isinstance(block, tuple)
|
||||||
|
else block
|
||||||
|
for block in mroots],
|
||||||
|
trunk if trunk is not None
|
||||||
|
else ft.reduce(
|
||||||
|
lambda x, y: y,
|
||||||
|
(block[1] for block in mroots
|
||||||
|
if isinstance(block, tuple)),
|
||||||
|
None))
|
||||||
|
|
||||||
# we seek around a bunch, so just keep the disk open
|
# we seek around a bunch, so just keep the disk open
|
||||||
with open(disk, 'rb') as f:
|
with open(disk, 'rb') as f:
|
||||||
@@ -4439,7 +4424,7 @@ def main(disk, mroots=None, paths=None, *,
|
|||||||
|
|
||||||
# fetch the filesystem
|
# fetch the filesystem
|
||||||
bd = Bd(f, block_size, block_count)
|
bd = Bd(f, block_size, block_count)
|
||||||
lfs = Lfs.fetch(bd, mroots)
|
lfs = Lfs.fetch(bd, mroots, trunk)
|
||||||
|
|
||||||
# print some information about the filesystem
|
# print some information about the filesystem
|
||||||
print('littlefs%s v%s.%s %sx%s %s w%s.%s, rev %08x, cksum %08x%s' % (
|
print('littlefs%s v%s.%s %sx%s %s w%s.%s, rev %08x, cksum %08x%s' % (
|
||||||
@@ -4503,7 +4488,7 @@ if __name__ == "__main__":
|
|||||||
def __call__(self, parser, namespace, values, option):
|
def __call__(self, parser, namespace, values, option):
|
||||||
for value in values:
|
for value in values:
|
||||||
# mroot?
|
# mroot?
|
||||||
if isinstance(value, list):
|
if not isinstance(value, str):
|
||||||
if getattr(namespace, 'mroots', None) is None:
|
if getattr(namespace, 'mroots', None) is None:
|
||||||
namespace.mroots = []
|
namespace.mroots = []
|
||||||
namespace.mroots.append(value)
|
namespace.mroots.append(value)
|
||||||
@@ -4525,6 +4510,10 @@ if __name__ == "__main__":
|
|||||||
action=AppendMrootOrPath,
|
action=AppendMrootOrPath,
|
||||||
help="Paths to show, must start with a leading slash. Defaults "
|
help="Paths to show, must start with a leading slash. Defaults "
|
||||||
"to the root directory.")
|
"to the root directory.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--trunk',
|
||||||
|
type=lambda x: int(x, 0),
|
||||||
|
help="Use this offset as the trunk of the mroots.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-b', '--block-size',
|
'-b', '--block-size',
|
||||||
type=bdgeom,
|
type=bdgeom,
|
||||||
|
|||||||
+85
-90
@@ -80,10 +80,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -114,7 +114,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def crc32c(data, crc=0):
|
def crc32c(data, crc=0):
|
||||||
crc ^= 0xffffffff
|
crc ^= 0xffffffff
|
||||||
@@ -471,9 +471,9 @@ class Rattr:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.data = data
|
self.data = data
|
||||||
@@ -547,9 +547,9 @@ class Ralt:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.jump = jump
|
self.jump = jump
|
||||||
@@ -602,9 +602,9 @@ class Rbyd:
|
|||||||
gcksumdelta=None,
|
gcksumdelta=None,
|
||||||
corrupt=False):
|
corrupt=False):
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.trunk = trunk
|
self.trunk = trunk
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
self.rev = rev
|
self.rev = rev
|
||||||
@@ -647,51 +647,7 @@ class Rbyd:
|
|||||||
return hash((frozenset(self.blocks), self.trunk))
|
return hash((frozenset(self.blocks), self.trunk))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def _fetch(cls, data, block, trunk=None):
|
||||||
# multiple blocks? unfortunately this must be a list
|
|
||||||
if isinstance(blocks, list):
|
|
||||||
# fetch all blocks
|
|
||||||
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
|
||||||
# determine most recent revision
|
|
||||||
i = 0
|
|
||||||
for i_, rbyd in enumerate(rbyds):
|
|
||||||
# compare with sequence arithmetic
|
|
||||||
if rbyd and (
|
|
||||||
not rbyds[i]
|
|
||||||
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
|
||||||
or (rbyd.rev == rbyds[i].rev
|
|
||||||
and rbyd.trunk > rbyds[i].trunk)):
|
|
||||||
i = i_
|
|
||||||
# keep track of the other blocks
|
|
||||||
rbyd = rbyds[i]
|
|
||||||
rbyd.blocks += tuple(
|
|
||||||
rbyds[(i+1+j) % len(rbyds)].block
|
|
||||||
for j in range(len(rbyds)-1))
|
|
||||||
# and patch the gcksumdelta if we have one
|
|
||||||
if rbyd.gcksumdelta is not None:
|
|
||||||
rbyd.gcksumdelta.blocks = rbyd.blocks
|
|
||||||
return rbyd
|
|
||||||
|
|
||||||
block = blocks
|
|
||||||
|
|
||||||
# blocks may also encode trunks
|
|
||||||
block, trunk = (
|
|
||||||
block[0] if isinstance(block, tuple)
|
|
||||||
else block,
|
|
||||||
trunk if trunk is not None
|
|
||||||
else block[1] if isinstance(block, tuple)
|
|
||||||
else None)
|
|
||||||
|
|
||||||
# bd can be either a bd reference or a preread block
|
|
||||||
#
|
|
||||||
# preread blocks can be useful for avoiding race conditions
|
|
||||||
# with cksums and shrubs
|
|
||||||
if isinstance(bd, Bd):
|
|
||||||
# seek/read the block
|
|
||||||
data = bd.readblock(block)
|
|
||||||
else:
|
|
||||||
data = bd
|
|
||||||
|
|
||||||
# fetch the rbyd
|
# fetch the rbyd
|
||||||
rev = fromle32(data[0:4])
|
rev = fromle32(data[0:4])
|
||||||
cksum = 0
|
cksum = 0
|
||||||
@@ -788,6 +744,39 @@ class Rbyd:
|
|||||||
gcksumdelta=gcksumdelta,
|
gcksumdelta=gcksumdelta,
|
||||||
corrupt=not trunk_)
|
corrupt=not trunk_)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
|
# multiple blocks?
|
||||||
|
if not isinstance(blocks, int):
|
||||||
|
# fetch all blocks
|
||||||
|
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
||||||
|
# determine most recent revision
|
||||||
|
i = 0
|
||||||
|
for i_, rbyd in enumerate(rbyds):
|
||||||
|
# compare with sequence arithmetic
|
||||||
|
if rbyd and (
|
||||||
|
not rbyds[i]
|
||||||
|
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
||||||
|
or (rbyd.rev == rbyds[i].rev
|
||||||
|
and rbyd.trunk > rbyds[i].trunk)):
|
||||||
|
i = i_
|
||||||
|
# keep track of the other blocks
|
||||||
|
rbyd = rbyds[i]
|
||||||
|
rbyd.blocks += tuple(
|
||||||
|
rbyds[(i+1+j) % len(rbyds)].block
|
||||||
|
for j in range(len(rbyds)-1))
|
||||||
|
# and patch the gcksumdelta if we have one
|
||||||
|
if rbyd.gcksumdelta is not None:
|
||||||
|
rbyd.gcksumdelta.blocks = rbyd.blocks
|
||||||
|
return rbyd
|
||||||
|
|
||||||
|
# seek/read the block
|
||||||
|
block = blocks
|
||||||
|
data = bd.readblock(block)
|
||||||
|
|
||||||
|
# fetch the rbyd
|
||||||
|
return cls._fetch(data, block, trunk)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# try to fetch the rbyd normally
|
# try to fetch the rbyd normally
|
||||||
@@ -804,6 +793,15 @@ class Rbyd:
|
|||||||
|
|
||||||
return rbyd
|
return rbyd
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, rbyd, trunk):
|
||||||
|
# steal the original rbyd's data
|
||||||
|
#
|
||||||
|
# this helps avoid race conditions with cksums and stuff
|
||||||
|
shrub = cls._fetch(rbyd.data, rbyd.block, trunk)
|
||||||
|
shrub.blocks = rbyd.blocks
|
||||||
|
return shrub
|
||||||
|
|
||||||
def lookupnext(self, rid, tag=None, *,
|
def lookupnext(self, rid, tag=None, *,
|
||||||
path=False):
|
path=False):
|
||||||
if not self or rid >= self.weight:
|
if not self or rid >= self.weight:
|
||||||
@@ -1172,32 +1170,21 @@ class Btree:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
# bd can either be a bd reference or a tuple of bd + data to
|
|
||||||
# avoid rereads, but we need a real bd reference somehow
|
|
||||||
if isinstance(bd, tuple):
|
|
||||||
bd, data = bd
|
|
||||||
else:
|
|
||||||
bd, data = bd, bd
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# rbyd fetch does most of the work here
|
# rbyd fetch does most of the work here
|
||||||
rbyd = Rbyd.fetch(data, blocks, trunk)
|
rbyd = Rbyd.fetch(bd, blocks, trunk)
|
||||||
return cls(bd, rbyd)
|
return cls(bd, rbyd)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# bd can either be a bd reference or a tuple of bd + data to
|
|
||||||
# avoid rereads, but we need a real bd reference somehow
|
|
||||||
if isinstance(bd, tuple):
|
|
||||||
bd, data = bd
|
|
||||||
else:
|
|
||||||
bd, data = bd, bd
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# rbyd fetchck does most of the work here
|
# rbyd fetchck does most of the work here
|
||||||
rbyd = Rbyd.fetchck(data, blocks, trunk, weight, cksum)
|
rbyd = Rbyd.fetchck(bd, blocks, trunk, weight, cksum)
|
||||||
return cls(bd, rbyd)
|
return cls(bd, rbyd)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, bd, rbyd, trunk):
|
||||||
|
shrub = Rbyd.fetchshrub(rbyd, trunk)
|
||||||
|
return cls(bd, shrub)
|
||||||
|
|
||||||
def lookupleaf(self, bid, *,
|
def lookupleaf(self, bid, *,
|
||||||
path=None,
|
path=None,
|
||||||
depth=None):
|
depth=None):
|
||||||
@@ -1770,13 +1757,9 @@ class Mdir:
|
|||||||
return hash(frozenset(self.blocks))
|
return hash(frozenset(self.blocks))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, mid, blocks):
|
def fetch(cls, bd, mid, blocks, trunk=None):
|
||||||
rbyd = Rbyd.fetch(bd, blocks)
|
rbyd = Rbyd.fetch(bd, blocks, trunk)
|
||||||
# this affects mbits
|
return cls(mid, rbyd, mbits=Mtree.mbits_(bd))
|
||||||
if isinstance(bd, Bd):
|
|
||||||
return cls(mid, rbyd, mbits=Mtree.mbits_(bd))
|
|
||||||
else:
|
|
||||||
return cls(mid, rbyd)
|
|
||||||
|
|
||||||
def lookup_(self, mid, tag=None, mask=None, *,
|
def lookup_(self, mid, tag=None, mask=None, *,
|
||||||
path=False):
|
path=False):
|
||||||
@@ -1965,11 +1948,8 @@ class Mtree:
|
|||||||
return hash(self.mrootanchor)
|
return hash(self.mrootanchor)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks=None, *,
|
def fetch(cls, bd, blocks=None, trunk=None, *,
|
||||||
depth=None):
|
depth=None):
|
||||||
# we need a real bd reference here
|
|
||||||
assert isinstance(bd, Bd)
|
|
||||||
|
|
||||||
# default to blocks 0x{0,1}
|
# default to blocks 0x{0,1}
|
||||||
if blocks is None:
|
if blocks is None:
|
||||||
blocks = [0, 1]
|
blocks = [0, 1]
|
||||||
@@ -1978,7 +1958,7 @@ class Mtree:
|
|||||||
mbits = Mtree.mbits_(bd)
|
mbits = Mtree.mbits_(bd)
|
||||||
|
|
||||||
# fetch the mrootanchor
|
# fetch the mrootanchor
|
||||||
mrootanchor = Mdir.fetch(bd, -1, blocks)
|
mrootanchor = Mdir.fetch(bd, -1, blocks, trunk)
|
||||||
|
|
||||||
# follow the mroot chain to try to find the active mroot
|
# follow the mroot chain to try to find the active mroot
|
||||||
mroot = mrootanchor
|
mroot = mrootanchor
|
||||||
@@ -2648,6 +2628,7 @@ class Mtree:
|
|||||||
|
|
||||||
|
|
||||||
def main(disk, mroots=None, *,
|
def main(disk, mroots=None, *,
|
||||||
|
trunk=None,
|
||||||
block_size=None,
|
block_size=None,
|
||||||
block_count=None,
|
block_count=None,
|
||||||
color='auto',
|
color='auto',
|
||||||
@@ -2667,9 +2648,19 @@ def main(disk, mroots=None, *,
|
|||||||
block_count = block_count_
|
block_count = block_count_
|
||||||
|
|
||||||
# flatten mroots, default to 0x{0,1}
|
# flatten mroots, default to 0x{0,1}
|
||||||
if not mroots:
|
mroots = list(it.chain.from_iterable(mroots)) if mroots else [0, 1]
|
||||||
mroots = [(0,1)]
|
|
||||||
mroots = [block for mroots_ in mroots for block in mroots_]
|
# mroots may also encode trunks
|
||||||
|
mroots, trunk = (
|
||||||
|
[block[0] if isinstance(block, tuple)
|
||||||
|
else block
|
||||||
|
for block in mroots],
|
||||||
|
trunk if trunk is not None
|
||||||
|
else ft.reduce(
|
||||||
|
lambda x, y: y,
|
||||||
|
(block[1] for block in mroots
|
||||||
|
if isinstance(block, tuple)),
|
||||||
|
None))
|
||||||
|
|
||||||
# we seek around a bunch, so just keep the disk open
|
# we seek around a bunch, so just keep the disk open
|
||||||
with open(disk, 'rb') as f:
|
with open(disk, 'rb') as f:
|
||||||
@@ -2680,7 +2671,7 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# fetch the mtree
|
# fetch the mtree
|
||||||
bd = Bd(f, block_size, block_count)
|
bd = Bd(f, block_size, block_count)
|
||||||
mtree = Mtree.fetch(bd, mroots,
|
mtree = Mtree.fetch(bd, mroots, trunk,
|
||||||
depth=args.get('depth'))
|
depth=args.get('depth'))
|
||||||
|
|
||||||
# print some information about the mtree
|
# print some information about the mtree
|
||||||
@@ -2899,6 +2890,10 @@ if __name__ == "__main__":
|
|||||||
nargs='*',
|
nargs='*',
|
||||||
type=rbydaddr,
|
type=rbydaddr,
|
||||||
help="Block address of the mroots. Defaults to 0x{0,1}.")
|
help="Block address of the mroots. Defaults to 0x{0,1}.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--trunk',
|
||||||
|
type=lambda x: int(x, 0),
|
||||||
|
help="Use this offset as the trunk of the mroots.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-b', '--block-size',
|
'-b', '--block-size',
|
||||||
type=bdgeom,
|
type=bdgeom,
|
||||||
|
|||||||
+73
-65
@@ -90,10 +90,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -124,7 +124,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
def crc32c(data, crc=0):
|
def crc32c(data, crc=0):
|
||||||
crc ^= 0xffffffff
|
crc ^= 0xffffffff
|
||||||
@@ -439,9 +439,9 @@ class Rattr:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.data = data
|
self.data = data
|
||||||
@@ -515,9 +515,9 @@ class Ralt:
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.toff = toff
|
self.toff = toff
|
||||||
self.tdata = tdata
|
self.tdata = tdata
|
||||||
self.jump = jump
|
self.jump = jump
|
||||||
@@ -570,9 +570,9 @@ class Rbyd:
|
|||||||
gcksumdelta=None,
|
gcksumdelta=None,
|
||||||
corrupt=False):
|
corrupt=False):
|
||||||
if isinstance(blocks, int):
|
if isinstance(blocks, int):
|
||||||
self.blocks = [blocks]
|
self.blocks = (blocks,)
|
||||||
else:
|
else:
|
||||||
self.blocks = list(blocks)
|
self.blocks = blocks
|
||||||
self.trunk = trunk
|
self.trunk = trunk
|
||||||
self.weight = weight
|
self.weight = weight
|
||||||
self.rev = rev
|
self.rev = rev
|
||||||
@@ -615,51 +615,7 @@ class Rbyd:
|
|||||||
return hash((frozenset(self.blocks), self.trunk))
|
return hash((frozenset(self.blocks), self.trunk))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, bd, blocks, trunk=None):
|
def _fetch(cls, data, block, trunk=None):
|
||||||
# multiple blocks? unfortunately this must be a list
|
|
||||||
if isinstance(blocks, list):
|
|
||||||
# fetch all blocks
|
|
||||||
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
|
||||||
# determine most recent revision
|
|
||||||
i = 0
|
|
||||||
for i_, rbyd in enumerate(rbyds):
|
|
||||||
# compare with sequence arithmetic
|
|
||||||
if rbyd and (
|
|
||||||
not rbyds[i]
|
|
||||||
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
|
||||||
or (rbyd.rev == rbyds[i].rev
|
|
||||||
and rbyd.trunk > rbyds[i].trunk)):
|
|
||||||
i = i_
|
|
||||||
# keep track of the other blocks
|
|
||||||
rbyd = rbyds[i]
|
|
||||||
rbyd.blocks += tuple(
|
|
||||||
rbyds[(i+1+j) % len(rbyds)].block
|
|
||||||
for j in range(len(rbyds)-1))
|
|
||||||
# and patch the gcksumdelta if we have one
|
|
||||||
if rbyd.gcksumdelta is not None:
|
|
||||||
rbyd.gcksumdelta.blocks = rbyd.blocks
|
|
||||||
return rbyd
|
|
||||||
|
|
||||||
block = blocks
|
|
||||||
|
|
||||||
# blocks may also encode trunks
|
|
||||||
block, trunk = (
|
|
||||||
block[0] if isinstance(block, tuple)
|
|
||||||
else block,
|
|
||||||
trunk if trunk is not None
|
|
||||||
else block[1] if isinstance(block, tuple)
|
|
||||||
else None)
|
|
||||||
|
|
||||||
# bd can be either a bd reference or a preread block
|
|
||||||
#
|
|
||||||
# preread blocks can be useful for avoiding race conditions
|
|
||||||
# with cksums and shrubs
|
|
||||||
if isinstance(bd, Bd):
|
|
||||||
# seek/read the block
|
|
||||||
data = bd.readblock(block)
|
|
||||||
else:
|
|
||||||
data = bd
|
|
||||||
|
|
||||||
# fetch the rbyd
|
# fetch the rbyd
|
||||||
rev = fromle32(data[0:4])
|
rev = fromle32(data[0:4])
|
||||||
cksum = 0
|
cksum = 0
|
||||||
@@ -756,6 +712,39 @@ class Rbyd:
|
|||||||
gcksumdelta=gcksumdelta,
|
gcksumdelta=gcksumdelta,
|
||||||
corrupt=not trunk_)
|
corrupt=not trunk_)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetch(cls, bd, blocks, trunk=None):
|
||||||
|
# multiple blocks?
|
||||||
|
if not isinstance(blocks, int):
|
||||||
|
# fetch all blocks
|
||||||
|
rbyds = [cls.fetch(bd, block, trunk) for block in blocks]
|
||||||
|
# determine most recent revision
|
||||||
|
i = 0
|
||||||
|
for i_, rbyd in enumerate(rbyds):
|
||||||
|
# compare with sequence arithmetic
|
||||||
|
if rbyd and (
|
||||||
|
not rbyds[i]
|
||||||
|
or not ((rbyd.rev - rbyds[i].rev) & 0x80000000)
|
||||||
|
or (rbyd.rev == rbyds[i].rev
|
||||||
|
and rbyd.trunk > rbyds[i].trunk)):
|
||||||
|
i = i_
|
||||||
|
# keep track of the other blocks
|
||||||
|
rbyd = rbyds[i]
|
||||||
|
rbyd.blocks += tuple(
|
||||||
|
rbyds[(i+1+j) % len(rbyds)].block
|
||||||
|
for j in range(len(rbyds)-1))
|
||||||
|
# and patch the gcksumdelta if we have one
|
||||||
|
if rbyd.gcksumdelta is not None:
|
||||||
|
rbyd.gcksumdelta.blocks = rbyd.blocks
|
||||||
|
return rbyd
|
||||||
|
|
||||||
|
# seek/read the block
|
||||||
|
block = blocks
|
||||||
|
data = bd.readblock(block)
|
||||||
|
|
||||||
|
# fetch the rbyd
|
||||||
|
return cls._fetch(data, block, trunk)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
def fetchck(cls, bd, blocks, trunk, weight, cksum):
|
||||||
# try to fetch the rbyd normally
|
# try to fetch the rbyd normally
|
||||||
@@ -772,6 +761,15 @@ class Rbyd:
|
|||||||
|
|
||||||
return rbyd
|
return rbyd
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fetchshrub(cls, rbyd, trunk):
|
||||||
|
# steal the original rbyd's data
|
||||||
|
#
|
||||||
|
# this helps avoid race conditions with cksums and stuff
|
||||||
|
shrub = cls._fetch(rbyd.data, rbyd.block, trunk)
|
||||||
|
shrub.blocks = rbyd.blocks
|
||||||
|
return shrub
|
||||||
|
|
||||||
def lookupnext(self, rid, tag=None, *,
|
def lookupnext(self, rid, tag=None, *,
|
||||||
path=False):
|
path=False):
|
||||||
if not self or rid >= self.weight:
|
if not self or rid >= self.weight:
|
||||||
@@ -1516,9 +1514,9 @@ def dbg_tree(rbyd, *,
|
|||||||
|
|
||||||
|
|
||||||
def main(disk, blocks=None, *,
|
def main(disk, blocks=None, *,
|
||||||
|
trunk=None,
|
||||||
block_size=None,
|
block_size=None,
|
||||||
block_count=None,
|
block_count=None,
|
||||||
trunk=None,
|
|
||||||
color='auto',
|
color='auto',
|
||||||
**args):
|
**args):
|
||||||
# figure out what color should be
|
# figure out what color should be
|
||||||
@@ -1536,9 +1534,19 @@ def main(disk, blocks=None, *,
|
|||||||
block_count = block_count_
|
block_count = block_count_
|
||||||
|
|
||||||
# flatten blocks, default to block 0
|
# flatten blocks, default to block 0
|
||||||
if not blocks:
|
blocks = list(it.chain.from_iterable(blocks)) if blocks else [0]
|
||||||
blocks = [(0,)]
|
|
||||||
blocks = [block for blocks_ in blocks for block in blocks_]
|
# blocks may also encode trunks
|
||||||
|
blocks, trunk = (
|
||||||
|
[block[0] if isinstance(block, tuple)
|
||||||
|
else block
|
||||||
|
for block in blocks],
|
||||||
|
trunk if trunk is not None
|
||||||
|
else ft.reduce(
|
||||||
|
lambda x, y: y,
|
||||||
|
(block[1] for block in blocks
|
||||||
|
if isinstance(block, tuple)),
|
||||||
|
None))
|
||||||
|
|
||||||
with open(disk, 'rb') as f:
|
with open(disk, 'rb') as f:
|
||||||
# if block_size is omitted, assume the block device is one big block
|
# if block_size is omitted, assume the block device is one big block
|
||||||
@@ -1548,7 +1556,7 @@ def main(disk, blocks=None, *,
|
|||||||
|
|
||||||
# fetch the rbyd
|
# fetch the rbyd
|
||||||
bd = Bd(f, block_size, block_count)
|
bd = Bd(f, block_size, block_count)
|
||||||
rbyd = Rbyd.fetch(bd, blocks)
|
rbyd = Rbyd.fetch(bd, blocks, trunk)
|
||||||
|
|
||||||
# print some information about the rbyd
|
# print some information about the rbyd
|
||||||
print('rbyd %s w%d, rev %08x, size %d, cksum %08x' % (
|
print('rbyd %s w%d, rev %08x, size %d, cksum %08x' % (
|
||||||
@@ -1587,6 +1595,10 @@ if __name__ == "__main__":
|
|||||||
nargs='*',
|
nargs='*',
|
||||||
type=rbydaddr,
|
type=rbydaddr,
|
||||||
help="Block address of metadata blocks.")
|
help="Block address of metadata blocks.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--trunk',
|
||||||
|
type=lambda x: int(x, 0),
|
||||||
|
help="Use this offset as the trunk of the tree.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-b', '--block-size',
|
'-b', '--block-size',
|
||||||
type=bdgeom,
|
type=bdgeom,
|
||||||
@@ -1595,10 +1607,6 @@ if __name__ == "__main__":
|
|||||||
'--block-count',
|
'--block-count',
|
||||||
type=lambda x: int(x, 0),
|
type=lambda x: int(x, 0),
|
||||||
help="Block count in blocks.")
|
help="Block count in blocks.")
|
||||||
parser.add_argument(
|
|
||||||
'--trunk',
|
|
||||||
type=lambda x: int(x, 0),
|
|
||||||
help="Use this offset as the trunk of the tree.")
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--color',
|
'--color',
|
||||||
choices=['never', 'always', 'auto'],
|
choices=['never', 'always', 'auto'],
|
||||||
|
|||||||
+5
-5
@@ -80,10 +80,10 @@ def bdgeom(s):
|
|||||||
return int(s, b)
|
return int(s, b)
|
||||||
|
|
||||||
# parse some rbyd addr encodings
|
# parse some rbyd addr encodings
|
||||||
# 0xa -> [0xa]
|
# 0xa -> (0xa,)
|
||||||
# 0xa.c -> [(0xa, 0xc)]
|
# 0xa.c -> ((0xa, 0xc),)
|
||||||
# 0x{a,b} -> [0xa, 0xb]
|
# 0x{a,b} -> (0xa, 0xb)
|
||||||
# 0x{a,b}.c -> [(0xa, 0xc), (0xb, 0xc)]
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
||||||
def rbydaddr(s):
|
def rbydaddr(s):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
b = 10
|
b = 10
|
||||||
@@ -114,7 +114,7 @@ def rbydaddr(s):
|
|||||||
else:
|
else:
|
||||||
addr.append(int(s, b))
|
addr.append(int(s, b))
|
||||||
|
|
||||||
return addr
|
return tuple(addr)
|
||||||
|
|
||||||
|
|
||||||
class RingIO:
|
class RingIO:
|
||||||
|
|||||||
Reference in New Issue
Block a user