mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
scripts: Ignore errors with compat-disabled gstate
The gbmap introduces quite a bit of complexity with how it interacts with config: block_count => gbmap weight, and wcompat => gbmap enabled. On one hand this means fewer sources of truth, on the other hand it makes the gbmap logic cross subsystems and a bit messy. To avoid trying to parse a bunch of disabled/garbage gstate, this adds wcompat/rcompat checks to our Gstate class, exposed via __bool__. This also means we actually need to parse wcompat/rcompat/ocompat flags, but that wasn't to difficult (though currently only supports 32-bits). --- I added conditional repr logic for the grm and gbmap, but didn't bother with the gcksum. The gcksum is used too many other places in these scripts to expect a nice rendering when disabled.
This commit is contained in:
@ -80,6 +80,24 @@ TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
|
||||
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
|
||||
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
|
||||
|
||||
RCOMPAT_NONSTANDARD = 0x00000001 # Non-standard filesystem format
|
||||
RCOMPAT_WRONLY = 0x00000002 # Reading is disallowed
|
||||
RCOMPAT_BMOSS = 0x00000010 # Files may use inlined data
|
||||
RCOMPAT_BSPROUT = 0x00000020 # Files may use block pointers
|
||||
RCOMPAT_BSHRUB = 0x00000040 # Files may use inlined btrees
|
||||
RCOMPAT_BTREE = 0x00000080 # Files may use btrees
|
||||
RCOMPAT_MMOSS = 0x00000100 # May use an inlined mdir
|
||||
RCOMPAT_MSPROUT = 0x00000200 # May use an mdir pointer
|
||||
RCOMPAT_MSHRUB = 0x00000400 # May use an inlined mtree
|
||||
RCOMPAT_MTREE = 0x00000800 # May use an mdir btree
|
||||
RCOMPAT_GRM = 0x00001000 # Global-remove in use
|
||||
|
||||
WCOMPAT_NONSTANDARD = 0x00000001 # Non-standard filesystem format
|
||||
WCOMPAT_RDONLY = 0x00000002 # Writing is disallowed
|
||||
WCOMPAT_DIR = 0x00000010 # Directory file types in use
|
||||
WCOMPAT_GCKSUM = 0x00001000 # Global-checksum in use
|
||||
WCOMPAT_GBMAP = 0x00002000 # Global on-disk block-map in use
|
||||
|
||||
|
||||
# assign chars/colors to specific filesystem objects
|
||||
CHARS = {
|
||||
@ -2544,6 +2562,13 @@ class Config:
|
||||
class Rcompat(Config):
|
||||
tag = TAG_RCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'rcompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2551,6 +2576,13 @@ class Config:
|
||||
class Wcompat(Config):
|
||||
tag = TAG_WCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'wcompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2558,6 +2590,13 @@ class Config:
|
||||
class Ocompat(Config):
|
||||
tag = TAG_OCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'ocompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2707,6 +2746,9 @@ class Gstate:
|
||||
class Gstate:
|
||||
tag = None
|
||||
mask = None
|
||||
rcompat = None
|
||||
wcompat = None
|
||||
ocompat = None
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
# replace tag with what we find
|
||||
@ -2723,11 +2765,31 @@ class Gstate:
|
||||
fillvalue=0))
|
||||
self.data = data
|
||||
|
||||
# check compat flags while we can access config
|
||||
if self.rcompat is not None:
|
||||
self.rcompat = self.rcompat & (
|
||||
int(config.rcompat) if config.rcompat is not None
|
||||
else 0)
|
||||
if self.wcompat is not None:
|
||||
self.wcompat = self.wcompat & (
|
||||
int(config.wcompat) if config.wcompat is not None
|
||||
else 0)
|
||||
if self.ocompat is not None:
|
||||
self.ocompat = self.ocompat & (
|
||||
int(config.ocompat) if config.ocompat is not None
|
||||
else 0)
|
||||
|
||||
@property
|
||||
def blocks(self):
|
||||
return tuple(it.chain.from_iterable(
|
||||
gdelta.blocks for _, gdelta in self.gdeltas))
|
||||
|
||||
# true unless compat flags are missing
|
||||
def __bool__(self):
|
||||
return (self.rcompat != 0
|
||||
and self.wcompat != 0
|
||||
and self.ocompat != 0)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return len(self.data)
|
||||
@ -2762,6 +2824,7 @@ class Gstate:
|
||||
# the global-checksum, cubed
|
||||
class Gcksum(Gstate):
|
||||
tag = TAG_GCKSUMDELTA
|
||||
wcompat = WCOMPAT_GCKSUM
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2776,6 +2839,7 @@ class Gstate:
|
||||
# any global-removes
|
||||
class Grm(Gstate):
|
||||
tag = TAG_GRMDELTA
|
||||
rcompat = RCOMPAT_GRM
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2794,11 +2858,16 @@ class Gstate:
|
||||
self.queue = queue
|
||||
|
||||
def repr(self):
|
||||
return 'grm [%s]' % ', '.join(mid.repr() for mid in self.queue)
|
||||
if self:
|
||||
return 'grm [%s]' % ', '.join(
|
||||
mid.repr() for mid in self.queue)
|
||||
else:
|
||||
return 'grm (unused)'
|
||||
|
||||
# the global block map
|
||||
class Gbmap(Gstate):
|
||||
tag = TAG_GBMAPDELTA
|
||||
wcompat = WCOMPAT_GBMAP
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2813,9 +2882,12 @@ class Gstate:
|
||||
cksum)
|
||||
|
||||
def repr(self):
|
||||
return 'gbmap %s 0x%x %d' % (
|
||||
self.btree.addr(),
|
||||
self.window, self.known)
|
||||
if self:
|
||||
return 'gbmap %s 0x%x %d' % (
|
||||
self.btree.addr(),
|
||||
self.window, self.known)
|
||||
else:
|
||||
return 'gbmap (unused)'
|
||||
|
||||
# keep track of known gstate
|
||||
_known = [g for g in Gstate.__subclasses__() if g.tag is not None]
|
||||
@ -3325,7 +3397,7 @@ class Lfs3:
|
||||
# traverse any gstate
|
||||
if not mtree_only and gstate:
|
||||
for gstate_ in self.gstate:
|
||||
if getattr(gstate_, 'btree', None) is None:
|
||||
if not gstate_ or getattr(gstate_, 'btree', None) is None:
|
||||
continue
|
||||
|
||||
for r in gstate_.btree.traverse(
|
||||
|
||||
@ -78,6 +78,24 @@ TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
|
||||
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
|
||||
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
|
||||
|
||||
RCOMPAT_NONSTANDARD = 0x00000001 # Non-standard filesystem format
|
||||
RCOMPAT_WRONLY = 0x00000002 # Reading is disallowed
|
||||
RCOMPAT_BMOSS = 0x00000010 # Files may use inlined data
|
||||
RCOMPAT_BSPROUT = 0x00000020 # Files may use block pointers
|
||||
RCOMPAT_BSHRUB = 0x00000040 # Files may use inlined btrees
|
||||
RCOMPAT_BTREE = 0x00000080 # Files may use btrees
|
||||
RCOMPAT_MMOSS = 0x00000100 # May use an inlined mdir
|
||||
RCOMPAT_MSPROUT = 0x00000200 # May use an mdir pointer
|
||||
RCOMPAT_MSHRUB = 0x00000400 # May use an inlined mtree
|
||||
RCOMPAT_MTREE = 0x00000800 # May use an mdir btree
|
||||
RCOMPAT_GRM = 0x00001000 # Global-remove in use
|
||||
|
||||
WCOMPAT_NONSTANDARD = 0x00000001 # Non-standard filesystem format
|
||||
WCOMPAT_RDONLY = 0x00000002 # Writing is disallowed
|
||||
WCOMPAT_DIR = 0x00000010 # Directory file types in use
|
||||
WCOMPAT_GCKSUM = 0x00001000 # Global-checksum in use
|
||||
WCOMPAT_GBMAP = 0x00002000 # Global on-disk block-map in use
|
||||
|
||||
|
||||
|
||||
# assign colors to specific filesystem objects
|
||||
@ -2574,6 +2592,13 @@ class Config:
|
||||
class Rcompat(Config):
|
||||
tag = TAG_RCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'rcompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2581,6 +2606,13 @@ class Config:
|
||||
class Wcompat(Config):
|
||||
tag = TAG_WCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'wcompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2588,6 +2620,13 @@ class Config:
|
||||
class Ocompat(Config):
|
||||
tag = TAG_OCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'ocompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2737,6 +2776,9 @@ class Gstate:
|
||||
class Gstate:
|
||||
tag = None
|
||||
mask = None
|
||||
rcompat = None
|
||||
wcompat = None
|
||||
ocompat = None
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
# replace tag with what we find
|
||||
@ -2753,11 +2795,31 @@ class Gstate:
|
||||
fillvalue=0))
|
||||
self.data = data
|
||||
|
||||
# check compat flags while we can access config
|
||||
if self.rcompat is not None:
|
||||
self.rcompat = self.rcompat & (
|
||||
int(config.rcompat) if config.rcompat is not None
|
||||
else 0)
|
||||
if self.wcompat is not None:
|
||||
self.wcompat = self.wcompat & (
|
||||
int(config.wcompat) if config.wcompat is not None
|
||||
else 0)
|
||||
if self.ocompat is not None:
|
||||
self.ocompat = self.ocompat & (
|
||||
int(config.ocompat) if config.ocompat is not None
|
||||
else 0)
|
||||
|
||||
@property
|
||||
def blocks(self):
|
||||
return tuple(it.chain.from_iterable(
|
||||
gdelta.blocks for _, gdelta in self.gdeltas))
|
||||
|
||||
# true unless compat flags are missing
|
||||
def __bool__(self):
|
||||
return (self.rcompat != 0
|
||||
and self.wcompat != 0
|
||||
and self.ocompat != 0)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return len(self.data)
|
||||
@ -2792,6 +2854,7 @@ class Gstate:
|
||||
# the global-checksum, cubed
|
||||
class Gcksum(Gstate):
|
||||
tag = TAG_GCKSUMDELTA
|
||||
wcompat = WCOMPAT_GCKSUM
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2806,6 +2869,7 @@ class Gstate:
|
||||
# any global-removes
|
||||
class Grm(Gstate):
|
||||
tag = TAG_GRMDELTA
|
||||
rcompat = RCOMPAT_GRM
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2824,11 +2888,16 @@ class Gstate:
|
||||
self.queue = queue
|
||||
|
||||
def repr(self):
|
||||
return 'grm [%s]' % ', '.join(mid.repr() for mid in self.queue)
|
||||
if self:
|
||||
return 'grm [%s]' % ', '.join(
|
||||
mid.repr() for mid in self.queue)
|
||||
else:
|
||||
return 'grm (unused)'
|
||||
|
||||
# the global block map
|
||||
class Gbmap(Gstate):
|
||||
tag = TAG_GBMAPDELTA
|
||||
wcompat = WCOMPAT_GBMAP
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2843,9 +2912,12 @@ class Gstate:
|
||||
cksum)
|
||||
|
||||
def repr(self):
|
||||
return 'gbmap %s 0x%x %d' % (
|
||||
self.btree.addr(),
|
||||
self.window, self.known)
|
||||
if self:
|
||||
return 'gbmap %s 0x%x %d' % (
|
||||
self.btree.addr(),
|
||||
self.window, self.known)
|
||||
else:
|
||||
return 'gbmap (unused)'
|
||||
|
||||
# keep track of known gstate
|
||||
_known = [g for g in Gstate.__subclasses__() if g.tag is not None]
|
||||
@ -3355,7 +3427,7 @@ class Lfs3:
|
||||
# traverse any gstate
|
||||
if not mtree_only and gstate:
|
||||
for gstate_ in self.gstate:
|
||||
if getattr(gstate_, 'btree', None) is None:
|
||||
if not gstate_ or getattr(gstate_, 'btree', None) is None:
|
||||
continue
|
||||
|
||||
for r in gstate_.btree.traverse(
|
||||
|
||||
@ -70,6 +70,24 @@ TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
|
||||
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
|
||||
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
|
||||
|
||||
RCOMPAT_NONSTANDARD = 0x00000001 # Non-standard filesystem format
|
||||
RCOMPAT_WRONLY = 0x00000002 # Reading is disallowed
|
||||
RCOMPAT_BMOSS = 0x00000010 # Files may use inlined data
|
||||
RCOMPAT_BSPROUT = 0x00000020 # Files may use block pointers
|
||||
RCOMPAT_BSHRUB = 0x00000040 # Files may use inlined btrees
|
||||
RCOMPAT_BTREE = 0x00000080 # Files may use btrees
|
||||
RCOMPAT_MMOSS = 0x00000100 # May use an inlined mdir
|
||||
RCOMPAT_MSPROUT = 0x00000200 # May use an mdir pointer
|
||||
RCOMPAT_MSHRUB = 0x00000400 # May use an inlined mtree
|
||||
RCOMPAT_MTREE = 0x00000800 # May use an mdir btree
|
||||
RCOMPAT_GRM = 0x00001000 # Global-remove in use
|
||||
|
||||
WCOMPAT_NONSTANDARD = 0x00000001 # Non-standard filesystem format
|
||||
WCOMPAT_RDONLY = 0x00000002 # Writing is disallowed
|
||||
WCOMPAT_DIR = 0x00000010 # Directory file types in use
|
||||
WCOMPAT_GCKSUM = 0x00001000 # Global-checksum in use
|
||||
WCOMPAT_GBMAP = 0x00002000 # Global on-disk block-map in use
|
||||
|
||||
|
||||
# some ways of block geometry representations
|
||||
# 512 -> 512
|
||||
@ -2469,6 +2487,13 @@ class Config:
|
||||
class Rcompat(Config):
|
||||
tag = TAG_RCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'rcompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2476,6 +2501,13 @@ class Config:
|
||||
class Wcompat(Config):
|
||||
tag = TAG_WCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'wcompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2483,6 +2515,13 @@ class Config:
|
||||
class Ocompat(Config):
|
||||
tag = TAG_OCOMPAT
|
||||
|
||||
def __init__(self, mroot, tag, rattr):
|
||||
super().__init__(mroot, tag, rattr)
|
||||
self.flags = fromle32(self.data)
|
||||
|
||||
def __int__(self):
|
||||
return self.flags
|
||||
|
||||
def repr(self):
|
||||
return 'ocompat 0x%s' % (
|
||||
''.join('%02x' % f for f in reversed(self.data)))
|
||||
@ -2632,6 +2671,9 @@ class Gstate:
|
||||
class Gstate:
|
||||
tag = None
|
||||
mask = None
|
||||
rcompat = None
|
||||
wcompat = None
|
||||
ocompat = None
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
# replace tag with what we find
|
||||
@ -2648,11 +2690,31 @@ class Gstate:
|
||||
fillvalue=0))
|
||||
self.data = data
|
||||
|
||||
# check compat flags while we can access config
|
||||
if self.rcompat is not None:
|
||||
self.rcompat = self.rcompat & (
|
||||
int(config.rcompat) if config.rcompat is not None
|
||||
else 0)
|
||||
if self.wcompat is not None:
|
||||
self.wcompat = self.wcompat & (
|
||||
int(config.wcompat) if config.wcompat is not None
|
||||
else 0)
|
||||
if self.ocompat is not None:
|
||||
self.ocompat = self.ocompat & (
|
||||
int(config.ocompat) if config.ocompat is not None
|
||||
else 0)
|
||||
|
||||
@property
|
||||
def blocks(self):
|
||||
return tuple(it.chain.from_iterable(
|
||||
gdelta.blocks for _, gdelta in self.gdeltas))
|
||||
|
||||
# true unless compat flags are missing
|
||||
def __bool__(self):
|
||||
return (self.rcompat != 0
|
||||
and self.wcompat != 0
|
||||
and self.ocompat != 0)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return len(self.data)
|
||||
@ -2687,6 +2749,7 @@ class Gstate:
|
||||
# the global-checksum, cubed
|
||||
class Gcksum(Gstate):
|
||||
tag = TAG_GCKSUMDELTA
|
||||
wcompat = WCOMPAT_GCKSUM
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2701,6 +2764,7 @@ class Gstate:
|
||||
# any global-removes
|
||||
class Grm(Gstate):
|
||||
tag = TAG_GRMDELTA
|
||||
rcompat = RCOMPAT_GRM
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2719,11 +2783,16 @@ class Gstate:
|
||||
self.queue = queue
|
||||
|
||||
def repr(self):
|
||||
return 'grm [%s]' % ', '.join(mid.repr() for mid in self.queue)
|
||||
if self:
|
||||
return 'grm [%s]' % ', '.join(
|
||||
mid.repr() for mid in self.queue)
|
||||
else:
|
||||
return 'grm (unused)'
|
||||
|
||||
# the global block map
|
||||
class Gbmap(Gstate):
|
||||
tag = TAG_GBMAPDELTA
|
||||
wcompat = WCOMPAT_GBMAP
|
||||
|
||||
def __init__(self, mtree, config, tag, gdeltas):
|
||||
super().__init__(mtree, config, tag, gdeltas)
|
||||
@ -2738,9 +2807,12 @@ class Gstate:
|
||||
cksum)
|
||||
|
||||
def repr(self):
|
||||
return 'gbmap %s 0x%x %d' % (
|
||||
self.btree.addr(),
|
||||
self.window, self.known)
|
||||
if self:
|
||||
return 'gbmap %s 0x%x %d' % (
|
||||
self.btree.addr(),
|
||||
self.window, self.known)
|
||||
else:
|
||||
return 'gbmap (unused)'
|
||||
|
||||
# keep track of known gstate
|
||||
_known = [g for g in Gstate.__subclasses__() if g.tag is not None]
|
||||
@ -3250,7 +3322,7 @@ class Lfs3:
|
||||
# traverse any gstate
|
||||
if not mtree_only and gstate:
|
||||
for gstate_ in self.gstate:
|
||||
if getattr(gstate_, 'btree', None) is None:
|
||||
if not gstate_ or getattr(gstate_, 'btree', None) is None:
|
||||
continue
|
||||
|
||||
for r in gstate_.btree.traverse(
|
||||
@ -4141,6 +4213,9 @@ def dbg_gstate(lfs, *,
|
||||
|
||||
# print gstate structures
|
||||
def dbg_gstruct(gstate):
|
||||
# not in use?
|
||||
if not gstate:
|
||||
return
|
||||
# no tree?
|
||||
if getattr(gstate, 'btree', None) is None:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user