mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 08:48:31 +01:00
Before, the tag format's type field was limited to 9-bits. This sounds
like a lot, but this field needed to encode up to 256 user-specified
types. This limited the flexibility of the encoded types. As time went
on, more bits in the type field were repurposed for various things,
leaving a rather fragile type field.
Here we make the jump to full 11-bit type fields. This comes at the cost
of a smaller length field, however the use of the length field was
always going to come with a RAM limitation. Rather than putting pressure
on RAM for inline files, the new type field lets us encode a chunk
number, splitting up inline files into multiple updatable units. This
actually pushes the theoretical inline max from 8KiB to 256KiB! (Note
that we only allow a single 1KiB chunk for now, chunky inline files
is just a theoretical future improvement).
Here is the new 32-bit tag format, note that there are multiple levels
of types which break down into more info:
[---- 32 ----]
[1|-- 11 --|-- 10 --|-- 10 --]
^. ^ . ^ ^- entry length
|. | . \------------ file id chunk info
|. \-----.------------------ type info (type3)
\.-----------.------------------ valid bit
[-3-|-- 8 --]
^ ^- chunk info
\------- type info (type1)
Additionally, I've split the CREATE tag into separate SPLICE and NAME
tags. This simplified the new compact logic a bit. For now, littlefs
still follows the rule that a NAME tag precedes any other tags related
to a file, but this can change in the future.
113 lines
3.0 KiB
Python
Executable File
113 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python2
|
|
|
|
import struct
|
|
import binascii
|
|
|
|
TYPES = {
|
|
(0x700, 0x400): 'splice',
|
|
(0x7ff, 0x401): 'create',
|
|
(0x7ff, 0x4ff): 'delete',
|
|
(0x700, 0x000): 'name',
|
|
(0x7ff, 0x001): 'name reg',
|
|
(0x7ff, 0x002): 'name dir',
|
|
(0x7ff, 0x0ff): 'name superblock',
|
|
(0x700, 0x200): 'struct',
|
|
(0x7ff, 0x200): 'struct dir',
|
|
(0x7ff, 0x202): 'struct ctz',
|
|
(0x7ff, 0x201): 'struct inline',
|
|
(0x700, 0x300): 'userattr',
|
|
(0x700, 0x600): 'tail',
|
|
(0x7ff, 0x600): 'tail soft',
|
|
(0x7ff, 0x601): 'tail hard',
|
|
(0x700, 0x700): 'gstate',
|
|
(0x7ff, 0x7ff): 'gstate move',
|
|
(0x700, 0x500): 'crc',
|
|
}
|
|
|
|
def typeof(type):
|
|
for prefix in range(12):
|
|
mask = 0x7ff & ~((1 << prefix)-1)
|
|
if (mask, type & mask) in TYPES:
|
|
return TYPES[mask, type & mask] + (
|
|
' %0*x' % (prefix/4, type & ((1 << prefix)-1))
|
|
if prefix else '')
|
|
else:
|
|
return '%02x' % type
|
|
|
|
def main(*blocks):
|
|
# find most recent block
|
|
file = None
|
|
rev = None
|
|
crc = None
|
|
versions = []
|
|
|
|
for block in blocks:
|
|
try:
|
|
nfile = open(block, 'rb')
|
|
ndata = nfile.read(4)
|
|
ncrc = binascii.crc32(ndata)
|
|
nrev, = struct.unpack('<I', ndata)
|
|
|
|
assert rev != nrev
|
|
if not file or ((rev - nrev) & 0x80000000):
|
|
file = nfile
|
|
rev = nrev
|
|
crc = ncrc
|
|
|
|
versions.append((nrev, '%s (rev %d)' % (block, nrev)))
|
|
except (IOError, struct.error):
|
|
pass
|
|
|
|
if not file:
|
|
print 'Bad metadata pair {%s}' % ', '.join(blocks)
|
|
return 1
|
|
|
|
print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True))
|
|
|
|
# go through each tag, print useful information
|
|
print "%-4s %-8s %-14s %3s %4s %s" % (
|
|
'off', 'tag', 'type', 'id', 'len', 'dump')
|
|
|
|
tag = 0xffffffff
|
|
off = 4
|
|
while True:
|
|
try:
|
|
data = file.read(4)
|
|
crc = binascii.crc32(data, crc)
|
|
ntag, = struct.unpack('>I', data)
|
|
except struct.error:
|
|
break
|
|
|
|
tag ^= ntag
|
|
off += 4
|
|
|
|
type = (tag & 0x7ff00000) >> 20
|
|
id = (tag & 0x000ffc00) >> 10
|
|
size = (tag & 0x000003ff) >> 0
|
|
iscrc = (type & 0x700) == 0x500
|
|
|
|
data = file.read(size if size != 0x3ff else 0)
|
|
if iscrc:
|
|
crc = binascii.crc32(data[:4], crc)
|
|
else:
|
|
crc = binascii.crc32(data, crc)
|
|
|
|
print '%04x: %08x %-15s %3s %4s %-23s %-8s' % (
|
|
off, tag,
|
|
typeof(type) + (' bad!' if iscrc and ~crc else ''),
|
|
id if id != 0x3ff else '.',
|
|
size if size != 0x3ff else 'x',
|
|
' '.join('%02x' % ord(c) for c in data[:8]),
|
|
''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8]))
|
|
|
|
off += size if size != 0x3ff else 0
|
|
if iscrc:
|
|
crc = 0
|
|
tag ^= (type & 1) << 31
|
|
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
sys.exit(main(*sys.argv[1:]))
|