Reworked how filesystem-level config is stored
Now, instead of storing a single contiguous block of config data, config
is stored as tagged metadata like any other attribute.
This allows more flexibility towards adding/removing config in the
future, without cluttering up the config with deprecated entries (see
ATA's "IDENTIFY DEVICE" response).
Most of the config entries are single leb128 limits on various integer
types, with the exception of the magic string and version (major/minor
pair).
---
Note this also includes some semantic changes to the config:
- Limits are stored as size-1. This avoid issues with integer overflow
at extreme ranges.
This was also adopted for block size (block limit) and block count
(disk limit). This deviation between on-disk config and user-facing
config risks confusion, but allows the potential for the full 2^31 range
for these values.
- The default cksum type, crc32c, has been changed to 0.
Originally this was 2 to allow the type to map to the crc width for
crc8, crc16, crc32c, crc64, etc. But dropping this idea and numbering
checksums as they are implemented simplifies things.
May come back to this.
- Storing these configs as attributes opens up of the option of on-disk
defaults when configs are missing.
I'm being a bit conservative with this one, as it's not clear to me if
we should prefer default configs (less code/storage, risk of untested
config parsing) or prefer explicit on-disk configs.
Currently the following have defaults since they seem the most obvious
to me:
- cksum type => defaults to crc32c
- redund type => defaults to parity (TODO, should this default to
no redund?)
- utag_limit => defaults to 0x7f (no special tag decoding)
- uattr_limit => defaults to block_limit (implicit)
This commit is contained in:
@@ -578,8 +578,19 @@ static int lfsr_bd_erase(lfs_t *lfs, lfs_block_t block) {
|
|||||||
enum lfsr_tag_type {
|
enum lfsr_tag_type {
|
||||||
LFSR_TAG_NULL = 0x0000,
|
LFSR_TAG_NULL = 0x0000,
|
||||||
|
|
||||||
LFSR_TAG_SUPERMAGIC = 0x0003,
|
LFSR_TAG_CONFIG = 0x0000,
|
||||||
LFSR_TAG_SUPERCONFIG = 0x0004,
|
LFSR_TAG_MAGIC = 0x0003,
|
||||||
|
LFSR_TAG_VERSION = 0x0004,
|
||||||
|
LFSR_TAG_FLAGS = 0x0005,
|
||||||
|
LFSR_TAG_CKSUMTYPE = 0x0006,
|
||||||
|
LFSR_TAG_REDUNDTYPE = 0x0007,
|
||||||
|
LFSR_TAG_BLOCKLIMIT = 0x0008,
|
||||||
|
LFSR_TAG_DISKLIMIT = 0x0009,
|
||||||
|
LFSR_TAG_MLEAFLIMIT = 0x000a,
|
||||||
|
LFSR_TAG_SIZELIMIT = 0x000b,
|
||||||
|
LFSR_TAG_NAMELIMIT = 0x000c,
|
||||||
|
LFSR_TAG_UTAGLIMIT = 0x000d,
|
||||||
|
LFSR_TAG_UATTRLIMIT = 0x000e,
|
||||||
|
|
||||||
LFSR_TAG_GSTATE = 0x0100,
|
LFSR_TAG_GSTATE = 0x0100,
|
||||||
LFSR_TAG_GRM = 0x0100,
|
LFSR_TAG_GRM = 0x0100,
|
||||||
@@ -6187,80 +6198,81 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
|
|||||||
|
|
||||||
/// Superblock things ///
|
/// Superblock things ///
|
||||||
|
|
||||||
// These are all leb128s, but we can expect smaller encodings
|
//// TODO rm?
|
||||||
// if we assume the version.
|
//// These are all leb128s, but we can expect smaller encodings
|
||||||
|
//// if we assume the version.
|
||||||
|
////
|
||||||
|
//// - 7-bit major_version => 1 byte leb128 (worst case)
|
||||||
|
//// - 7-bit minor_version => 1 byte leb128 (worst case)
|
||||||
|
//// - 7-bit cksum_type => 1 byte leb128 (worst case)
|
||||||
|
//// - 7-bit flags => 1 byte leb128 (worst case)
|
||||||
|
//// - 32-bit block_size => 5 byte leb128 (worst case)
|
||||||
|
//// - 32-bit block_count => 5 byte leb128 (worst case)
|
||||||
|
//// - 7-bit utag_limit => 1 byte leb128 (worst case)
|
||||||
|
//// - 32-bit mtree_limit => 5 byte leb128 (worst case)
|
||||||
|
//// - 32-bit attr_limit => 5 byte leb128 (worst case)
|
||||||
|
//// - 32-bit name_limit => 5 byte leb128 (worst case)
|
||||||
|
//// - 32-bit file_limit => 5 byte leb128 (worst case)
|
||||||
|
//// => 33 bytes total
|
||||||
|
////
|
||||||
|
//#define LFSR_SUPERCONFIG_DSIZE (1+1+1+1+5+5+1+5+5+5+5)
|
||||||
//
|
//
|
||||||
// - 7-bit major_version => 1 byte leb128 (worst case)
|
//#define LFSR_DATA_FROMSUPERCONFIG(_lfs, _buffer)
|
||||||
// - 7-bit minor_version => 1 byte leb128 (worst case)
|
// lfsr_data_fromsuperconfig(_lfs, _buffer)
|
||||||
// - 7-bit cksum_type => 1 byte leb128 (worst case)
|
|
||||||
// - 7-bit flags => 1 byte leb128 (worst case)
|
|
||||||
// - 32-bit block_size => 5 byte leb128 (worst case)
|
|
||||||
// - 32-bit block_count => 5 byte leb128 (worst case)
|
|
||||||
// - 7-bit utag_limit => 1 byte leb128 (worst case)
|
|
||||||
// - 32-bit mtree_limit => 5 byte leb128 (worst case)
|
|
||||||
// - 32-bit attr_limit => 5 byte leb128 (worst case)
|
|
||||||
// - 32-bit name_limit => 5 byte leb128 (worst case)
|
|
||||||
// - 32-bit file_limit => 5 byte leb128 (worst case)
|
|
||||||
// => 33 bytes total
|
|
||||||
//
|
//
|
||||||
#define LFSR_SUPERCONFIG_DSIZE (1+1+1+1+5+5+1+5+5+5+5)
|
//static lfsr_data_t lfsr_data_fromsuperconfig(lfs_t *lfs,
|
||||||
|
// uint8_t buffer[static LFSR_SUPERCONFIG_DSIZE]) {
|
||||||
#define LFSR_DATA_FROMSUPERCONFIG(_lfs, _buffer) \
|
// // TODO most of these should also be in the lfs_config/lfs_t structs
|
||||||
lfsr_data_fromsuperconfig(_lfs, _buffer)
|
//
|
||||||
|
// // note we take a shortcut for for single-byte leb128s, but these
|
||||||
static lfsr_data_t lfsr_data_fromsuperconfig(lfs_t *lfs,
|
// // are still leb128s! the top bit must be zero!
|
||||||
uint8_t buffer[static LFSR_SUPERCONFIG_DSIZE]) {
|
//
|
||||||
// TODO most of these should also be in the lfs_config/lfs_t structs
|
// // on-disk major version
|
||||||
|
// buffer[0] = LFS_DISK_VERSION_MAJOR;
|
||||||
// note we take a shortcut for for single-byte leb128s, but these
|
// // on-disk minor version
|
||||||
// are still leb128s! the top bit must be zero!
|
// buffer[1] = LFS_DISK_VERSION_MINOR;
|
||||||
|
// // on-disk cksum type
|
||||||
// on-disk major version
|
// buffer[2] = 2;
|
||||||
buffer[0] = LFS_DISK_VERSION_MAJOR;
|
// // on-disk flags
|
||||||
// on-disk minor version
|
// buffer[3] = 0;
|
||||||
buffer[1] = LFS_DISK_VERSION_MINOR;
|
//
|
||||||
// on-disk cksum type
|
// // on-disk block size
|
||||||
buffer[2] = 2;
|
// lfs_ssize_t d = 4;
|
||||||
// on-disk flags
|
// lfs_ssize_t d_ = lfs_toleb128(lfs->cfg->block_size, &buffer[d], 5);
|
||||||
buffer[3] = 0;
|
// LFS_ASSERT(d_ >= 0);
|
||||||
|
// d += d_;
|
||||||
// on-disk block size
|
//
|
||||||
lfs_ssize_t d = 4;
|
// // on-disk block count
|
||||||
lfs_ssize_t d_ = lfs_toleb128(lfs->cfg->block_size, &buffer[d], 5);
|
// d_ = lfs_toleb128(lfs->cfg->block_count, &buffer[d], 5);
|
||||||
LFS_ASSERT(d_ >= 0);
|
// LFS_ASSERT(d_ >= 0);
|
||||||
d += d_;
|
// d += d_;
|
||||||
|
//
|
||||||
// on-disk block count
|
// // on-disk mleaf limit
|
||||||
d_ = lfs_toleb128(lfs->cfg->block_count, &buffer[d], 5);
|
// d_ = lfs_toleb128(lfsr_mleafweight(lfs)-1, &buffer[d], 5);
|
||||||
LFS_ASSERT(d_ >= 0);
|
// LFS_ASSERT(d_ >= 0);
|
||||||
d += d_;
|
// d += d_;
|
||||||
|
//
|
||||||
// on-disk mleaf limit
|
// // on-disk utag limit
|
||||||
d_ = lfs_toleb128(lfsr_mleafweight(lfs)-1, &buffer[d], 5);
|
// buffer[d] = 0x7f;
|
||||||
LFS_ASSERT(d_ >= 0);
|
// d += 1;
|
||||||
d += d_;
|
//
|
||||||
|
// // on-disk attr limit
|
||||||
// on-disk utag limit
|
// d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
|
||||||
buffer[d] = 0x7f;
|
// LFS_ASSERT(d_ >= 0);
|
||||||
d += 1;
|
// d += d_;
|
||||||
|
//
|
||||||
// on-disk attr limit
|
// // on-disk name limit
|
||||||
d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
|
// d_ = lfs_toleb128(0xff, &buffer[d], 5);
|
||||||
LFS_ASSERT(d_ >= 0);
|
// LFS_ASSERT(d_ >= 0);
|
||||||
d += d_;
|
// d += d_;
|
||||||
|
//
|
||||||
// on-disk name limit
|
// // on-disk file limit
|
||||||
d_ = lfs_toleb128(0xff, &buffer[d], 5);
|
// d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
|
||||||
LFS_ASSERT(d_ >= 0);
|
// LFS_ASSERT(d_ >= 0);
|
||||||
d += d_;
|
// d += d_;
|
||||||
|
//
|
||||||
// on-disk file limit
|
// return LFSR_DATA_BUF(buffer, d);
|
||||||
d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
|
//}
|
||||||
LFS_ASSERT(d_ >= 0);
|
|
||||||
d += d_;
|
|
||||||
|
|
||||||
return LFSR_DATA_BUF(buffer, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Filesystem init functions ///
|
/// Filesystem init functions ///
|
||||||
@@ -6304,13 +6316,16 @@ static int lfsr_mountinited(lfs_t *lfs) {
|
|||||||
if (mdir->mid == -1) {
|
if (mdir->mid == -1) {
|
||||||
// has magic string?
|
// has magic string?
|
||||||
lfsr_data_t data;
|
lfsr_data_t data;
|
||||||
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SUPERMAGIC,
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_MAGIC,
|
||||||
NULL, &data);
|
NULL, &data);
|
||||||
if (err && err != LFS_ERR_NOENT) {
|
if (err) {
|
||||||
|
if (err == LFS_ERR_NOENT) {
|
||||||
|
LFS_ERROR("No littlefs magic found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != LFS_ERR_NOENT) {
|
|
||||||
lfs_scmp_t cmp = lfsr_data_cmp(lfs, &data, "littlefs", 8);
|
lfs_scmp_t cmp = lfsr_data_cmp(lfs, &data, "littlefs", 8);
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
return cmp;
|
return cmp;
|
||||||
@@ -6318,201 +6333,308 @@ static int lfsr_mountinited(lfs_t *lfs) {
|
|||||||
|
|
||||||
// treat corrupted magic as no magic
|
// treat corrupted magic as no magic
|
||||||
if (lfs_cmp(cmp) != 0) {
|
if (lfs_cmp(cmp) != 0) {
|
||||||
err = LFS_ERR_NOENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_NOENT) {
|
|
||||||
LFS_ERROR("No littlefs magic found");
|
LFS_ERROR("No littlefs magic found");
|
||||||
return LFS_ERR_INVAL;
|
return LFS_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup the superconfig
|
// check the disk version
|
||||||
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SUPERCONFIG,
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_VERSION,
|
||||||
|
NULL, &data);
|
||||||
|
if (err) {
|
||||||
|
if (err == LFS_ERR_NOENT) {
|
||||||
|
LFS_ERROR("No littlefs version found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t major_version;
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&major_version);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
major_version = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t minor_version;
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&minor_version);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
minor_version = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (major_version != LFS_DISK_VERSION_MAJOR
|
||||||
|
|| minor_version > LFS_DISK_VERSION_MINOR) {
|
||||||
|
LFS_ERROR("Incompatible version v%"PRId32".%"PRId32
|
||||||
|
" (!= v%"PRId32".%"PRId32")",
|
||||||
|
major_version,
|
||||||
|
minor_version,
|
||||||
|
LFS_DISK_VERSION_MAJOR,
|
||||||
|
LFS_DISK_VERSION_MINOR);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for any flags
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_FLAGS,
|
||||||
|
NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = 0;
|
||||||
|
if (err != LFS_ERR_NOENT) {
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&flags);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
flags = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags != 0) {
|
||||||
|
LFS_ERROR("Incompatible flags 0x%"PRIx32, flags);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check checksum type
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_CKSUMTYPE,
|
||||||
|
NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cksum_type = 0;
|
||||||
|
if (err != LFS_ERR_NOENT) {
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&cksum_type);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
cksum_type = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cksum_type != 0) {
|
||||||
|
LFS_ERROR("Incompatible cksum type 0x%"PRId32, cksum_type);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check redundancy type
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_REDUNDTYPE,
|
||||||
|
NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t redund_type = 0;
|
||||||
|
if (err != LFS_ERR_NOENT) {
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&redund_type);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
redund_type = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redund_type != 0) {
|
||||||
|
LFS_ERROR("Incompatible redund type 0x%"PRId32, redund_type);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check block limit / block size
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_BLOCKLIMIT,
|
||||||
|
NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t block_limit = 0;
|
||||||
|
if (err != LFS_ERR_NOENT) {
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&block_limit);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
block_limit = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block_limit != lfs->cfg->block_size-1) {
|
||||||
|
LFS_ERROR("Incompatible block size %"PRId32" "
|
||||||
|
"(!= %"PRId32")",
|
||||||
|
block_limit+1,
|
||||||
|
lfs->cfg->block_size);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check disk limit / block count
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_DISKLIMIT,
|
||||||
|
NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t disk_limit = 0;
|
||||||
|
if (err != LFS_ERR_NOENT) {
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&disk_limit);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
disk_limit = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disk_limit != lfs->cfg->block_count-1) {
|
||||||
|
LFS_ERROR("Incompatible block count %"PRId32" "
|
||||||
|
"(!= %"PRId32")",
|
||||||
|
disk_limit+1,
|
||||||
|
lfs->cfg->block_count);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the mleaf limit
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_MLEAFLIMIT,
|
||||||
|
NULL, &data);
|
||||||
|
if (err) {
|
||||||
|
if (err == LFS_ERR_NOENT) {
|
||||||
|
LFS_ERROR("No mleaf limit found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mleaf_limit;
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&mleaf_limit);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
mleaf_limit = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only support power-of-two mleaf weights, this unlikely to
|
||||||
|
// ever to change since mleaf weights are pretty arbitrary
|
||||||
|
if (lfs_popc(mleaf_limit+1) != 1) {
|
||||||
|
LFS_ERROR("Incompatible mleaf weight %"PRId32, mleaf_limit+1);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs->mleaf_bits = lfs_nlog2(mleaf_limit);
|
||||||
|
|
||||||
|
// read the size limit
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SIZELIMIT,
|
||||||
|
NULL, &data);
|
||||||
|
if (err) {
|
||||||
|
if (err == LFS_ERR_NOENT) {
|
||||||
|
LFS_ERROR("No size limit found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size_limit;
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&size_limit);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
size_limit = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size_limit > lfs->size_limit) {
|
||||||
|
LFS_ERROR("Incompatible size limit (%"PRId32" > %"PRId32")",
|
||||||
|
size_limit,
|
||||||
|
lfs->size_limit);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs->size_limit = size_limit;
|
||||||
|
|
||||||
|
// read the name limit
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_NAMELIMIT,
|
||||||
|
NULL, &data);
|
||||||
|
if (err) {
|
||||||
|
if (err == LFS_ERR_NOENT) {
|
||||||
|
LFS_ERROR("No name limit found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t name_limit;
|
||||||
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&name_limit);
|
||||||
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
name_limit = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name_limit > lfs->name_limit) {
|
||||||
|
LFS_ERROR("Incompatible name limit (%"PRId32" > %"PRId32")",
|
||||||
|
name_limit,
|
||||||
|
lfs->name_limit);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs->name_limit = name_limit;
|
||||||
|
|
||||||
|
// check the utag limit
|
||||||
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_UTAGLIMIT,
|
||||||
NULL, &data);
|
NULL, &data);
|
||||||
if (err && err != LFS_ERR_NOENT) {
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != LFS_ERR_NOENT) {
|
if (err != LFS_ERR_NOENT) {
|
||||||
// check the major/minor version
|
uint32_t utag_limit;
|
||||||
int32_t major_version;
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&utag_limit);
|
||||||
int32_t minor_version;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, &major_version);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != LFS_ERR_CORRUPT) {
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, &minor_version);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
|
utag_limit = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT
|
// only 7-bit utags are supported
|
||||||
|| major_version != LFS_DISK_VERSION_MAJOR
|
if (utag_limit != 0x7f) {
|
||||||
|| minor_version > LFS_DISK_VERSION_MINOR) {
|
LFS_ERROR("Incompatible utag limit "
|
||||||
LFS_ERROR("Incompatible version v%"PRId32".%"PRId32
|
"(%"PRId32" != %"PRId32")",
|
||||||
" (!= v%"PRId32".%"PRId32")",
|
utag_limit,
|
||||||
(err ? -1 : major_version),
|
|
||||||
(err ? -1 : minor_version),
|
|
||||||
LFS_DISK_VERSION_MAJOR,
|
|
||||||
LFS_DISK_VERSION_MINOR);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the on-disk cksum type
|
|
||||||
int32_t cksum_type;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, &cksum_type);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT || cksum_type != 2) {
|
|
||||||
LFS_ERROR("Incompatible cksum type 0x%"PRIx32
|
|
||||||
" (!= 0x%"PRIx32")",
|
|
||||||
(err ? -1 : cksum_type),
|
|
||||||
2);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for any on-disk flags
|
|
||||||
int32_t flags;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, &flags);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT || flags != 0) {
|
|
||||||
LFS_ERROR("Incompatible flags 0x%"PRIx32
|
|
||||||
" (!= 0x%"PRIx32")",
|
|
||||||
(err ? -1 : flags),
|
|
||||||
0);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the on-disk block size
|
|
||||||
// TODO actually use this
|
|
||||||
lfs_size_t block_size;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&block_size);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT
|
|
||||||
|| block_size != lfs->cfg->block_size) {
|
|
||||||
LFS_ERROR("Incompatible block size 0x%"PRIx32
|
|
||||||
" (!= 0x%"PRIx32")",
|
|
||||||
(err ? (lfs_size_t)-1 : block_size),
|
|
||||||
lfs->cfg->block_size);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the on-disk block count
|
|
||||||
// TODO actually use this
|
|
||||||
lfs_block_t block_count;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&block_count);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT
|
|
||||||
|| block_count != lfs->cfg->block_count) {
|
|
||||||
LFS_ERROR("Incompatible block count 0x%"PRIx32
|
|
||||||
" (!= 0x%"PRIx32")",
|
|
||||||
(err ? (lfs_block_t)-1 : block_count),
|
|
||||||
lfs->cfg->block_count);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the on-disk mtree limit
|
|
||||||
// TODO actually use this
|
|
||||||
lfsr_mid_t mleaf_limit;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&mleaf_limit);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT
|
|
||||||
|| mleaf_limit != lfsr_mleafweight(lfs)-1) {
|
|
||||||
LFS_ERROR("Incompatible mleaf limit 0x%"PRIx32,
|
|
||||||
(err ? (lfsr_mid_t)-1 : mleaf_limit));
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the on-disk utag limit
|
|
||||||
// TODO actually use this
|
|
||||||
int32_t utag_limit;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, &utag_limit);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT || utag_limit != 0x7f) {
|
|
||||||
LFS_ERROR("Incompatible utag limit 0x%"PRIx32
|
|
||||||
" (> 0x%"PRIx32")",
|
|
||||||
(err ? -1 : utag_limit),
|
|
||||||
0x7f);
|
0x7f);
|
||||||
return LFS_ERR_INVAL;
|
return LFS_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check the on-disk attr limit
|
// check the uattr limit
|
||||||
// TODO actually use this
|
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_UATTRLIMIT,
|
||||||
lfs_ssize_t attr_limit;
|
NULL, &data);
|
||||||
err = lfsr_data_readleb128(lfs, &data, &attr_limit);
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT || attr_limit != 0x7fffffff) {
|
if (err != LFS_ERR_NOENT) {
|
||||||
LFS_ERROR("Incompatible attr limit 0x%"PRIx32
|
uint32_t uattr_limit;
|
||||||
" (> 0x%"PRIx32")",
|
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&uattr_limit);
|
||||||
(err ? -1 : attr_limit),
|
|
||||||
0x7fffffff);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the on-disk name limit
|
|
||||||
// TODO actually use this
|
|
||||||
lfs_ssize_t name_limit;
|
|
||||||
err = lfsr_data_readleb128(lfs, &data, &name_limit);
|
|
||||||
// treat any leb128 overflows as out-of-range values
|
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
if (err == LFS_ERR_CORRUPT || name_limit != 0xff) {
|
uattr_limit = -1;
|
||||||
LFS_ERROR("Incompatible name limit 0x%"PRIx32
|
|
||||||
" (> 0x%"PRIx32")",
|
|
||||||
(err ? -1 : name_limit),
|
|
||||||
0xff);
|
|
||||||
return LFS_ERR_INVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the on-disk file limit
|
// only >=block_size uattrs are (implicitly) supported
|
||||||
// TODO actually use this
|
if (uattr_limit < lfs->cfg->block_size-1) {
|
||||||
lfs_soff_t file_limit;
|
LFS_ERROR("Incompatible uattr limit "
|
||||||
err = lfsr_data_readleb128(lfs, &data, &file_limit);
|
"(%"PRId32" < %"PRId32")",
|
||||||
// treat any leb128 overflows as out-of-range values
|
uattr_limit,
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
lfs->cfg->block_size-1);
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == LFS_ERR_CORRUPT || file_limit != 0x7fffffff) {
|
|
||||||
LFS_ERROR("Incompatible file limit 0x%"PRIx32
|
|
||||||
" (> 0x%"PRIx32")",
|
|
||||||
(err ? -1 : file_limit),
|
|
||||||
0x7fffffff);
|
|
||||||
return LFS_ERR_INVAL;
|
return LFS_ERR_INVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6563,11 +6685,6 @@ static int lfsr_mountinited(lfs_t *lfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int lfsr_formatinited(lfs_t *lfs) {
|
static int lfsr_formatinited(lfs_t *lfs) {
|
||||||
// create superconfig
|
|
||||||
uint8_t superconfig_buf[LFSR_SUPERCONFIG_DSIZE];
|
|
||||||
lfsr_data_t superconfig_data = lfsr_data_fromsuperconfig(lfs,
|
|
||||||
superconfig_buf);
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
// write superblock to both rbyds in the root mroot to hopefully
|
// write superblock to both rbyds in the root mroot to hopefully
|
||||||
// avoid mounting an older filesystem on disk
|
// avoid mounting an older filesystem on disk
|
||||||
@@ -6588,11 +6705,18 @@ static int lfsr_formatinited(lfs_t *lfs) {
|
|||||||
|
|
||||||
// our initial superblock contains a couple things:
|
// our initial superblock contains a couple things:
|
||||||
// - our magic string, "littlefs"
|
// - our magic string, "littlefs"
|
||||||
// - the superconfig, format-time configuration
|
// - any format-time configuration
|
||||||
// - the root's bookmark tag, which reserves did = 0 for the root
|
// - the root's bookmark tag, which reserves did = 0 for the root
|
||||||
err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
|
err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
|
||||||
LFSR_ATTR(-1, SUPERMAGIC, 0, BUF("littlefs", 8)),
|
LFSR_ATTR(-1, MAGIC, 0, BUF("littlefs", 8)),
|
||||||
LFSR_ATTR(-1, SUPERCONFIG, 0, DATA(superconfig_data)),
|
LFSR_ATTR(-1, VERSION, 0, BUF(((const uint8_t[2]){
|
||||||
|
LFS_DISK_VERSION_MAJOR,
|
||||||
|
LFS_DISK_VERSION_MINOR}), 2)),
|
||||||
|
LFSR_ATTR(-1, BLOCKLIMIT, 0, LEB128(lfs->cfg->block_size-1)),
|
||||||
|
LFSR_ATTR(-1, DISKLIMIT, 0, LEB128(lfs->cfg->block_count-1)),
|
||||||
|
LFSR_ATTR(-1, MLEAFLIMIT, 0, LEB128(lfsr_mleafweight(lfs)-1)),
|
||||||
|
LFSR_ATTR(-1, SIZELIMIT, 0, LEB128(0x7fffffff)),
|
||||||
|
LFSR_ATTR(-1, NAMELIMIT, 0, LEB128(0xff)),
|
||||||
LFSR_ATTR(0, BOOKMARK, +1, NAME(0, NULL, 0))));
|
LFSR_ATTR(0, BOOKMARK, +1, NAME(0, NULL, 0))));
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -6794,7 +6918,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check that name fits
|
// check that name fits
|
||||||
if (name_size > lfs->name_max) {
|
if (name_size > lfs->name_limit) {
|
||||||
return LFS_ERR_NAMETOOLONG;
|
return LFS_ERR_NAMETOOLONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7019,7 +7143,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
|
|||||||
// there are a few cases we need to watch out for
|
// there are a few cases we need to watch out for
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
// check that name fits
|
// check that name fits
|
||||||
if (new_name_size > lfs->name_max) {
|
if (new_name_size > lfs->name_limit) {
|
||||||
return LFS_ERR_NAMETOOLONG;
|
return LFS_ERR_NAMETOOLONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10848,26 +10972,18 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
lfs->lookahead.acked = 0;
|
lfs->lookahead.acked = 0;
|
||||||
|
|
||||||
// check that the size limits are sane
|
// check that the size limits are sane
|
||||||
LFS_ASSERT(lfs->cfg->name_max <= LFS_NAME_MAX);
|
LFS_ASSERT(lfs->cfg->name_limit <= LFS_NAME_MAX);
|
||||||
lfs->name_max = lfs->cfg->name_max;
|
lfs->name_limit = lfs->cfg->name_limit;
|
||||||
if (!lfs->name_max) {
|
if (!lfs->name_limit) {
|
||||||
lfs->name_max = LFS_NAME_MAX;
|
lfs->name_limit = LFS_NAME_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX);
|
LFS_ASSERT(lfs->cfg->size_limit <= LFS_FILE_MAX);
|
||||||
lfs->file_max = lfs->cfg->file_max;
|
lfs->size_limit = lfs->cfg->size_limit;
|
||||||
if (!lfs->file_max) {
|
if (!lfs->size_limit) {
|
||||||
lfs->file_max = LFS_FILE_MAX;
|
lfs->size_limit = LFS_FILE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT(lfs->cfg->attr_max <= LFS_ATTR_MAX);
|
|
||||||
lfs->attr_max = lfs->cfg->attr_max;
|
|
||||||
if (!lfs->attr_max) {
|
|
||||||
lfs->attr_max = LFS_ATTR_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
|
|
||||||
|
|
||||||
// setup default state
|
// setup default state
|
||||||
lfs->root[0] = LFS_BLOCK_NULL;
|
lfs->root[0] = LFS_BLOCK_NULL;
|
||||||
lfs->root[1] = LFS_BLOCK_NULL;
|
lfs->root[1] = LFS_BLOCK_NULL;
|
||||||
|
|||||||
@@ -75,11 +75,12 @@ typedef int32_t lfsr_sdid_t;
|
|||||||
#define LFS_FILE_MAX 2147483647
|
#define LFS_FILE_MAX 2147483647
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Maximum size of custom attributes in bytes, may be redefined, but there is
|
// TODO rm me
|
||||||
// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
|
//// Maximum size of custom attributes in bytes, may be redefined, but there is
|
||||||
#ifndef LFS_ATTR_MAX
|
//// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
|
||||||
#define LFS_ATTR_MAX 1022
|
//#ifndef LFS_ATTR_MAX
|
||||||
#endif
|
//#define LFS_ATTR_MAX 1022
|
||||||
|
//#endif
|
||||||
|
|
||||||
// Possible error codes, these are negative to allow
|
// Possible error codes, these are negative to allow
|
||||||
// valid positive return values
|
// valid positive return values
|
||||||
@@ -261,23 +262,24 @@ struct lfs_config {
|
|||||||
// larger names except the size of the info struct which is controlled by
|
// larger names except the size of the info struct which is controlled by
|
||||||
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
|
// the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
|
||||||
// superblock and must be respected by other littlefs drivers.
|
// superblock and must be respected by other littlefs drivers.
|
||||||
lfs_size_t name_max;
|
lfs_size_t name_limit;
|
||||||
|
|
||||||
// Optional upper limit on files in bytes. No downside for larger files
|
// Optional upper limit on files in bytes. No downside for larger files
|
||||||
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
|
// but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
|
||||||
// in superblock and must be respected by other littlefs drivers.
|
// in superblock and must be respected by other littlefs drivers.
|
||||||
lfs_size_t file_max;
|
lfs_size_t size_limit;
|
||||||
|
|
||||||
// Optional upper limit on custom attributes in bytes. No downside for
|
// TODO rm me
|
||||||
// larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
// // Optional upper limit on custom attributes in bytes. No downside for
|
||||||
// LFS_ATTR_MAX when zero.
|
// // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
|
||||||
lfs_size_t attr_max;
|
// // LFS_ATTR_MAX when zero.
|
||||||
|
// lfs_size_t attr_max;
|
||||||
// Optional upper limit on total space given to metadata pairs in bytes. On
|
//
|
||||||
// devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
|
// // Optional upper limit on total space given to metadata pairs in bytes. On
|
||||||
// can help bound the metadata compaction time. Must be <= block_size.
|
// // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
|
||||||
// Defaults to block_size when zero.
|
// // can help bound the metadata compaction time. Must be <= block_size.
|
||||||
lfs_size_t metadata_max;
|
// // Defaults to block_size when zero.
|
||||||
|
// lfs_size_t metadata_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
// File info structure
|
// File info structure
|
||||||
@@ -505,9 +507,8 @@ typedef struct lfs {
|
|||||||
} lookahead;
|
} lookahead;
|
||||||
|
|
||||||
const struct lfs_config *cfg;
|
const struct lfs_config *cfg;
|
||||||
lfs_size_t name_max;
|
lfs_size_t name_limit;
|
||||||
lfs_size_t file_max;
|
lfs_off_t size_limit;
|
||||||
lfs_size_t attr_max;
|
|
||||||
|
|
||||||
// begin lfsr things
|
// begin lfsr things
|
||||||
lfsr_grm_t grm;
|
lfsr_grm_t grm;
|
||||||
|
|||||||
+28
-8
@@ -9,8 +9,19 @@ import struct
|
|||||||
|
|
||||||
|
|
||||||
TAG_NULL = 0x0000
|
TAG_NULL = 0x0000
|
||||||
TAG_SUPERMAGIC = 0x0003
|
TAG_CONFIG = 0x0000
|
||||||
TAG_SUPERCONFIG = 0x0004
|
TAG_MAGIC = 0x0003
|
||||||
|
TAG_VERSION = 0x0004
|
||||||
|
TAG_FLAGS = 0x0005
|
||||||
|
TAG_CKSUMTYPE = 0x0006
|
||||||
|
TAG_REDUNDTYPE = 0x0007
|
||||||
|
TAG_BLOCKLIMIT = 0x0008
|
||||||
|
TAG_DISKLIMIT = 0x0009
|
||||||
|
TAG_MLEAFLIMIT = 0x000a
|
||||||
|
TAG_SIZELIMIT = 0x000b
|
||||||
|
TAG_NAMELIMIT = 0x000c
|
||||||
|
TAG_UTAGLIMIT = 0x000d
|
||||||
|
TAG_UATTRLIMIT = 0x000e
|
||||||
TAG_GSTATE = 0x0100
|
TAG_GSTATE = 0x0100
|
||||||
TAG_GRM = 0x0100
|
TAG_GRM = 0x0100
|
||||||
TAG_NAME = 0x0200
|
TAG_NAME = 0x0200
|
||||||
@@ -122,12 +133,21 @@ def tagrepr(tag, w, size, off=None):
|
|||||||
return 'null%s%s' % (
|
return 'null%s%s' % (
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
' %d' % size if size else '')
|
' %d' % size if size else '')
|
||||||
elif tag == TAG_SUPERMAGIC:
|
elif (tag & 0xff00) == TAG_CONFIG:
|
||||||
return 'supermagic%s %d' % (
|
return '%s%s %d' % (
|
||||||
' w%d' % w if w else '',
|
'magic' if tag == TAG_MAGIC
|
||||||
size)
|
else 'version' if tag == TAG_VERSION
|
||||||
elif tag == TAG_SUPERCONFIG:
|
else 'flags' if tag == TAG_FLAGS
|
||||||
return 'superconfig%s %d' % (
|
else 'cksumtype' if tag == TAG_CKSUMTYPE
|
||||||
|
else 'redundtype' if tag == TAG_REDUNDTYPE
|
||||||
|
else 'blocklimit' if tag == TAG_BLOCKLIMIT
|
||||||
|
else 'disklimit' if tag == TAG_DISKLIMIT
|
||||||
|
else 'mleaflimit' if tag == TAG_MLEAFLIMIT
|
||||||
|
else 'sizelimit' if tag == TAG_SIZELIMIT
|
||||||
|
else 'namelimit' if tag == TAG_NAMELIMIT
|
||||||
|
else 'utaglimit' if tag == TAG_UTAGLIMIT
|
||||||
|
else 'uattrlimit' if tag == TAG_UATTRLIMIT
|
||||||
|
else 'config 0x%02x' % (tag & 0xff),
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
size)
|
size)
|
||||||
elif (tag & 0xff00) == TAG_GSTATE:
|
elif (tag & 0xff00) == TAG_GSTATE:
|
||||||
|
|||||||
+207
-60
@@ -10,8 +10,19 @@ import struct
|
|||||||
|
|
||||||
|
|
||||||
TAG_NULL = 0x0000
|
TAG_NULL = 0x0000
|
||||||
TAG_SUPERMAGIC = 0x0003
|
TAG_CONFIG = 0x0000
|
||||||
TAG_SUPERCONFIG = 0x0004
|
TAG_MAGIC = 0x0003
|
||||||
|
TAG_VERSION = 0x0004
|
||||||
|
TAG_FLAGS = 0x0005
|
||||||
|
TAG_CKSUMTYPE = 0x0006
|
||||||
|
TAG_REDUNDTYPE = 0x0007
|
||||||
|
TAG_BLOCKLIMIT = 0x0008
|
||||||
|
TAG_DISKLIMIT = 0x0009
|
||||||
|
TAG_MLEAFLIMIT = 0x000a
|
||||||
|
TAG_SIZELIMIT = 0x000b
|
||||||
|
TAG_NAMELIMIT = 0x000c
|
||||||
|
TAG_UTAGLIMIT = 0x000d
|
||||||
|
TAG_UATTRLIMIT = 0x000e
|
||||||
TAG_GSTATE = 0x0100
|
TAG_GSTATE = 0x0100
|
||||||
TAG_GRM = 0x0100
|
TAG_GRM = 0x0100
|
||||||
TAG_NAME = 0x0200
|
TAG_NAME = 0x0200
|
||||||
@@ -132,12 +143,21 @@ def tagrepr(tag, w, size, off=None):
|
|||||||
return 'null%s%s' % (
|
return 'null%s%s' % (
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
' %d' % size if size else '')
|
' %d' % size if size else '')
|
||||||
elif tag == TAG_SUPERMAGIC:
|
elif (tag & 0xff00) == TAG_CONFIG:
|
||||||
return 'supermagic%s %d' % (
|
return '%s%s %d' % (
|
||||||
' w%d' % w if w else '',
|
'magic' if tag == TAG_MAGIC
|
||||||
size)
|
else 'version' if tag == TAG_VERSION
|
||||||
elif tag == TAG_SUPERCONFIG:
|
else 'flags' if tag == TAG_FLAGS
|
||||||
return 'superconfig%s %d' % (
|
else 'cksumtype' if tag == TAG_CKSUMTYPE
|
||||||
|
else 'redundtype' if tag == TAG_REDUNDTYPE
|
||||||
|
else 'blocklimit' if tag == TAG_BLOCKLIMIT
|
||||||
|
else 'disklimit' if tag == TAG_DISKLIMIT
|
||||||
|
else 'mleaflimit' if tag == TAG_MLEAFLIMIT
|
||||||
|
else 'sizelimit' if tag == TAG_SIZELIMIT
|
||||||
|
else 'namelimit' if tag == TAG_NAMELIMIT
|
||||||
|
else 'utaglimit' if tag == TAG_UTAGLIMIT
|
||||||
|
else 'uattrlimit' if tag == TAG_UATTRLIMIT
|
||||||
|
else 'config 0x%02x' % (tag & 0xff),
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
size)
|
size)
|
||||||
elif (tag & 0xff00) == TAG_GSTATE:
|
elif (tag & 0xff00) == TAG_GSTATE:
|
||||||
@@ -625,32 +645,164 @@ class Rbyd:
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# read the superconfig
|
# read the config
|
||||||
def superconfig(mroot):
|
class Config:
|
||||||
done, rid, tag, w, j, d, data, _ = mroot.lookup(-1, TAG_SUPERCONFIG)
|
def __init__(self, mroot=None):
|
||||||
if done or rid != -1 or tag != TAG_SUPERCONFIG:
|
# read the config from the mroot
|
||||||
return {}
|
self.config = {}
|
||||||
j += d
|
if mroot is not None:
|
||||||
|
tag = 0
|
||||||
|
while True:
|
||||||
|
done, rid, tag, w, j, d, data, _ = mroot.lookup(-1, tag+0x1)
|
||||||
|
if done or rid != -1 or (tag & 0xff00) != TAG_CONFIG:
|
||||||
|
break
|
||||||
|
|
||||||
config = co.OrderedDict()
|
self.config[tag] = (j+d, data)
|
||||||
|
|
||||||
|
# accessors for known config
|
||||||
|
@ft.cached_property
|
||||||
|
def magic(self):
|
||||||
|
if TAG_MAGIC in self.config:
|
||||||
|
_, data = self.config[TAG_MAGIC]
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def version(self):
|
||||||
|
if TAG_VERSION in self.config:
|
||||||
|
_, data = self.config[TAG_VERSION]
|
||||||
d = 0
|
d = 0
|
||||||
def next(name):
|
major, d_ = fromleb128(data[d:]); d += d_
|
||||||
nonlocal config, d
|
minor, d_ = fromleb128(data[d:]); d += d_
|
||||||
c, d_ = fromleb128(data[d:])
|
return (major, minor)
|
||||||
config[name] = (c, j, data[d:d+d_])
|
else:
|
||||||
d += d_
|
return (None, None)
|
||||||
next('major_version')
|
|
||||||
next('minor_version')
|
@ft.cached_property
|
||||||
next('csum_type')
|
def flags(self):
|
||||||
next('flags')
|
if TAG_FLAGS in self.config:
|
||||||
next('block_size')
|
_, data = self.config[TAG_FLAGS]
|
||||||
next('block_count')
|
flags, _ = fromleb128(data)
|
||||||
next('mlimit')
|
return flags
|
||||||
next('utag_limit')
|
else:
|
||||||
next('attr_limit')
|
return None
|
||||||
next('name_limit')
|
|
||||||
next('file_limit')
|
@ft.cached_property
|
||||||
return config
|
def cksum_type(self):
|
||||||
|
if TAG_CKSUMTYPE in self.config:
|
||||||
|
_, data = self.config[TAG_CKSUMTYPE]
|
||||||
|
cksum_type, _ = fromleb128(data)
|
||||||
|
return cksum_type
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def redund_type(self):
|
||||||
|
if TAG_REDUNDTYPE in self.config:
|
||||||
|
_, data = self.config[TAG_REDUNDTYPE]
|
||||||
|
redund_type, _ = fromleb128(data)
|
||||||
|
return redund_type
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def block_limit(self):
|
||||||
|
if TAG_BLOCKLIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_BLOCKLIMIT]
|
||||||
|
block_limit, _ = fromleb128(data)
|
||||||
|
return block_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def disk_limit(self):
|
||||||
|
if TAG_DISKLIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_DISKLIMIT]
|
||||||
|
disk_limit, _ = fromleb128(data)
|
||||||
|
return disk_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def mleaf_limit(self):
|
||||||
|
if TAG_MLEAFLIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_MLEAFLIMIT]
|
||||||
|
mleaf_limit, _ = fromleb128(data)
|
||||||
|
return mleaf_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def size_limit(self):
|
||||||
|
if TAG_SIZELIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_SIZELIMIT]
|
||||||
|
size_limit, _ = fromleb128(data)
|
||||||
|
return size_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def name_limit(self):
|
||||||
|
if TAG_NAMELIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_NAMELIMIT]
|
||||||
|
name_limit, _ = fromleb128(data)
|
||||||
|
return name_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def utag_limit(self):
|
||||||
|
if TAG_UTAGLIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_UTAGLIMIT]
|
||||||
|
utag_limit, _ = fromleb128(data)
|
||||||
|
return utag_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@ft.cached_property
|
||||||
|
def uattr_limit(self):
|
||||||
|
if TAG_UATTRLIMIT in self.config:
|
||||||
|
_, data = self.config[TAG_UATTRLIMIT]
|
||||||
|
uattr_limit, _ = fromleb128(data)
|
||||||
|
return uattr_limit
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def repr(self):
|
||||||
|
def crepr(tag, data):
|
||||||
|
if tag == TAG_MAGIC:
|
||||||
|
return 'magic \"%s\"' % ''.join(
|
||||||
|
b if b >= ' ' and b <= '~' else '.'
|
||||||
|
for b in map(chr, self.magic))
|
||||||
|
elif tag == TAG_VERSION:
|
||||||
|
return 'version v%d.%d' % self.version
|
||||||
|
elif tag == TAG_FLAGS:
|
||||||
|
return 'flags 0x%x' % self.flags
|
||||||
|
elif tag == TAG_CKSUMTYPE:
|
||||||
|
return 'cksum_type %d' % self.cksum_type
|
||||||
|
elif tag == TAG_REDUNDTYPE:
|
||||||
|
return 'redund_type %d' % self.redund_type
|
||||||
|
elif tag == TAG_BLOCKLIMIT:
|
||||||
|
return 'block_limit %d' % self.block_limit
|
||||||
|
elif tag == TAG_DISKLIMIT:
|
||||||
|
return 'disk_limit %d' % self.disk_limit
|
||||||
|
elif tag == TAG_MLEAFLIMIT:
|
||||||
|
return 'mleaf_limit %d' % self.mleaf_limit
|
||||||
|
elif tag == TAG_SIZELIMIT:
|
||||||
|
return 'size_limit %d' % self.size_limit
|
||||||
|
elif tag == TAG_NAMELIMIT:
|
||||||
|
return 'name_limit %d' % self.name_limit
|
||||||
|
elif tag == TAG_UTAGLIMIT:
|
||||||
|
return 'utag_limit %d' % self.utag_limit
|
||||||
|
elif tag == TAG_UATTRLIMIT:
|
||||||
|
return 'uattr_limit %d' % self.uattr_limit
|
||||||
|
else:
|
||||||
|
return 'config 0x%02x %d' % (tag, len(data))
|
||||||
|
|
||||||
|
for tag, (j, data) in sorted(self.config.items()):
|
||||||
|
yield crepr(tag, data), tag, j, data
|
||||||
|
|
||||||
|
|
||||||
# collect gstate
|
# collect gstate
|
||||||
class GState:
|
class GState:
|
||||||
@@ -695,26 +847,22 @@ class GState:
|
|||||||
mid % self.mleaf_weight))
|
mid % self.mleaf_weight))
|
||||||
return rms
|
return rms
|
||||||
|
|
||||||
def grepr(tag, data, mleaf_weight):
|
def repr(self):
|
||||||
|
def grepr(tag, data):
|
||||||
if tag == TAG_GRM:
|
if tag == TAG_GRM:
|
||||||
d = 0
|
count, _ = fromleb128(data)
|
||||||
count, d_ = fromleb128(data[d:]); d += d_
|
|
||||||
rms = []
|
|
||||||
if count <= 2:
|
|
||||||
for _ in range(count):
|
|
||||||
mid, d_ = fromleb128(data[d:]); d += d_
|
|
||||||
rms.append((
|
|
||||||
mid - (mid % mleaf_weight),
|
|
||||||
mid % mleaf_weight))
|
|
||||||
return 'grm %s' % (
|
return 'grm %s' % (
|
||||||
'none' if count == 0
|
'none' if count == 0
|
||||||
else ' '.join('%d.%d' % (mbid//mleaf_weight, rid)
|
else ' '.join('%d.%d' % (mbid//self.mleaf_weight, rid)
|
||||||
for mbid, rid in rms)
|
for mbid, rid in self.grm)
|
||||||
if count <= 2
|
if count <= 2
|
||||||
else '0x%x' % count)
|
else '0x%x %d' % (count, len(data)))
|
||||||
else:
|
else:
|
||||||
return 'gstate 0x%02x %d' % (tag, len(data))
|
return 'gstate 0x%02x %d' % (tag, len(data))
|
||||||
|
|
||||||
|
for tag, data in sorted(self.gstate.items()):
|
||||||
|
yield grepr(tag, data), tag, data
|
||||||
|
|
||||||
def frepr(mdir, rid, tag):
|
def frepr(mdir, rid, tag):
|
||||||
if tag == TAG_BOOKMARK:
|
if tag == TAG_BOOKMARK:
|
||||||
# read the did
|
# read the did
|
||||||
@@ -770,14 +918,14 @@ def main(disk, mroots=None, *,
|
|||||||
# - find the actual mroot
|
# - find the actual mroot
|
||||||
# - find the total weight
|
# - find the total weight
|
||||||
# - are we corrupted?
|
# - are we corrupted?
|
||||||
# - collect superconfig
|
# - collect config
|
||||||
# - collect gstate
|
# - collect gstate
|
||||||
# - any missing or orphaned bookmark entries
|
# - any missing or orphaned bookmark entries
|
||||||
bweight = 0
|
bweight = 0
|
||||||
rweight = 0
|
rweight = 0
|
||||||
corrupted = False
|
corrupted = False
|
||||||
gstate = GState(mleaf_weight)
|
gstate = GState(mleaf_weight)
|
||||||
config = {}
|
config = Config()
|
||||||
dir_dids = [(0, b'', -1, 0, None, -1, TAG_DID, 0)]
|
dir_dids = [(0, b'', -1, 0, None, -1, TAG_DID, 0)]
|
||||||
bookmark_dids = []
|
bookmark_dids = []
|
||||||
|
|
||||||
@@ -792,8 +940,8 @@ 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, 0, mroot)
|
gstate.xor(-1, 0, mroot)
|
||||||
# get the superconfig
|
# get the config
|
||||||
config = superconfig(mroot)
|
config = Config(mroot)
|
||||||
|
|
||||||
# find any dids
|
# find any dids
|
||||||
for rid, tag, w, j, d, data in mroot:
|
for rid, tag, w, j, d, data in mroot:
|
||||||
@@ -942,8 +1090,8 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# print some information about the filesystem
|
# print some information about the filesystem
|
||||||
print('littlefs v%s.%s %s, rev %d, weight %d.%d' % (
|
print('littlefs v%s.%s %s, rev %d, weight %d.%d' % (
|
||||||
config.get('major_version', ('?',))[0],
|
config.version[0] if config.version[0] is not None else '?',
|
||||||
config.get('minor_version', ('?',))[0],
|
config.version[1] if config.version[1] is not None else '?',
|
||||||
mroot.addr(), mroot.rev, bweight//mleaf_weight, 1*mleaf_weight))
|
mroot.addr(), mroot.rev, bweight//mleaf_weight, 1*mleaf_weight))
|
||||||
|
|
||||||
# print header
|
# print header
|
||||||
@@ -964,12 +1112,12 @@ def main(disk, mroots=None, *,
|
|||||||
'data (truncated)'
|
'data (truncated)'
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|
||||||
# print superconfig?
|
# print config?
|
||||||
if args.get('config'):
|
if args.get('config'):
|
||||||
for i, (name, (c, j, data)) in enumerate(config.items()):
|
for i, (repr_, tag, j, data) in enumerate(config.repr()):
|
||||||
print('%12s %-*s %s' % (
|
print('%12s %-*s %s' % (
|
||||||
'config:' if i == 0 else '',
|
'config:' if i == 0 else '',
|
||||||
w_width + 23, '%s %d' % (name, c),
|
w_width + 23, repr_,
|
||||||
next(xxd(data, 8), '')
|
next(xxd(data, 8), '')
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|
||||||
@@ -979,7 +1127,7 @@ def main(disk, mroots=None, *,
|
|||||||
'',
|
'',
|
||||||
w_width, '',
|
w_width, '',
|
||||||
'%-22s%s' % (
|
'%-22s%s' % (
|
||||||
'%08x' % c,
|
'%04x %08x %07x' % (tag, 0, len(data)),
|
||||||
' %s' % ' '.join(
|
' %s' % ' '.join(
|
||||||
'%08x' % fromle32(
|
'%08x' % fromle32(
|
||||||
data[i*4 : min(i*4+4,len(data))])
|
data[i*4 : min(i*4+4,len(data))])
|
||||||
@@ -998,11 +1146,10 @@ def main(disk, mroots=None, *,
|
|||||||
|
|
||||||
# print gstate?
|
# print gstate?
|
||||||
if args.get('gstate'):
|
if args.get('gstate'):
|
||||||
for i, (tag, data) in enumerate(sorted(gstate.gstate.items())):
|
for i, (repr_, tag, data) in enumerate(gstate.repr()):
|
||||||
print('%12s %-*s %s' % (
|
print('%12s %-*s %s' % (
|
||||||
'gstate:' if i == 0 else '',
|
'gstate:' if i == 0 else '',
|
||||||
w_width + 23,
|
w_width + 23, repr_,
|
||||||
grepr(tag, data, mleaf_weight),
|
|
||||||
next(xxd(data, 8), '')
|
next(xxd(data, 8), '')
|
||||||
if not args.get('no_truncate') else ''))
|
if not args.get('no_truncate') else ''))
|
||||||
|
|
||||||
@@ -1253,9 +1400,9 @@ if __name__ == "__main__":
|
|||||||
default='auto',
|
default='auto',
|
||||||
help="When to use terminal colors. Defaults to 'auto'.")
|
help="When to use terminal colors. Defaults to 'auto'.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-c', '--config', '--superconfig',
|
'-c', '--config',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help="Show the on-disk superconfig.")
|
help="Show the on-disk config.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-g', '--gstate',
|
'-g', '--gstate',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
|||||||
+28
-8
@@ -9,8 +9,19 @@ import struct
|
|||||||
|
|
||||||
|
|
||||||
TAG_NULL = 0x0000
|
TAG_NULL = 0x0000
|
||||||
TAG_SUPERMAGIC = 0x0003
|
TAG_CONFIG = 0x0000
|
||||||
TAG_SUPERCONFIG = 0x0004
|
TAG_MAGIC = 0x0003
|
||||||
|
TAG_VERSION = 0x0004
|
||||||
|
TAG_FLAGS = 0x0005
|
||||||
|
TAG_CKSUMTYPE = 0x0006
|
||||||
|
TAG_REDUNDTYPE = 0x0007
|
||||||
|
TAG_BLOCKLIMIT = 0x0008
|
||||||
|
TAG_DISKLIMIT = 0x0009
|
||||||
|
TAG_MLEAFLIMIT = 0x000a
|
||||||
|
TAG_SIZELIMIT = 0x000b
|
||||||
|
TAG_NAMELIMIT = 0x000c
|
||||||
|
TAG_UTAGLIMIT = 0x000d
|
||||||
|
TAG_UATTRLIMIT = 0x000e
|
||||||
TAG_GSTATE = 0x0100
|
TAG_GSTATE = 0x0100
|
||||||
TAG_GRM = 0x0100
|
TAG_GRM = 0x0100
|
||||||
TAG_NAME = 0x0200
|
TAG_NAME = 0x0200
|
||||||
@@ -131,12 +142,21 @@ def tagrepr(tag, w, size, off=None):
|
|||||||
return 'null%s%s' % (
|
return 'null%s%s' % (
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
' %d' % size if size else '')
|
' %d' % size if size else '')
|
||||||
elif tag == TAG_SUPERMAGIC:
|
elif (tag & 0xff00) == TAG_CONFIG:
|
||||||
return 'supermagic%s %d' % (
|
return '%s%s %d' % (
|
||||||
' w%d' % w if w else '',
|
'magic' if tag == TAG_MAGIC
|
||||||
size)
|
else 'version' if tag == TAG_VERSION
|
||||||
elif tag == TAG_SUPERCONFIG:
|
else 'flags' if tag == TAG_FLAGS
|
||||||
return 'superconfig%s %d' % (
|
else 'cksumtype' if tag == TAG_CKSUMTYPE
|
||||||
|
else 'redundtype' if tag == TAG_REDUNDTYPE
|
||||||
|
else 'blocklimit' if tag == TAG_BLOCKLIMIT
|
||||||
|
else 'disklimit' if tag == TAG_DISKLIMIT
|
||||||
|
else 'mleaflimit' if tag == TAG_MLEAFLIMIT
|
||||||
|
else 'sizelimit' if tag == TAG_SIZELIMIT
|
||||||
|
else 'namelimit' if tag == TAG_NAMELIMIT
|
||||||
|
else 'utaglimit' if tag == TAG_UTAGLIMIT
|
||||||
|
else 'uattrlimit' if tag == TAG_UATTRLIMIT
|
||||||
|
else 'config 0x%02x' % (tag & 0xff),
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
size)
|
size)
|
||||||
elif (tag & 0xff00) == TAG_GSTATE:
|
elif (tag & 0xff00) == TAG_GSTATE:
|
||||||
|
|||||||
+28
-8
@@ -18,8 +18,19 @@ COLORS = [
|
|||||||
|
|
||||||
|
|
||||||
TAG_NULL = 0x0000
|
TAG_NULL = 0x0000
|
||||||
TAG_SUPERMAGIC = 0x0003
|
TAG_CONFIG = 0x0000
|
||||||
TAG_SUPERCONFIG = 0x0004
|
TAG_MAGIC = 0x0003
|
||||||
|
TAG_VERSION = 0x0004
|
||||||
|
TAG_FLAGS = 0x0005
|
||||||
|
TAG_CKSUMTYPE = 0x0006
|
||||||
|
TAG_REDUNDTYPE = 0x0007
|
||||||
|
TAG_BLOCKLIMIT = 0x0008
|
||||||
|
TAG_DISKLIMIT = 0x0009
|
||||||
|
TAG_MLEAFLIMIT = 0x000a
|
||||||
|
TAG_SIZELIMIT = 0x000b
|
||||||
|
TAG_NAMELIMIT = 0x000c
|
||||||
|
TAG_UTAGLIMIT = 0x000d
|
||||||
|
TAG_UATTRLIMIT = 0x000e
|
||||||
TAG_GSTATE = 0x0100
|
TAG_GSTATE = 0x0100
|
||||||
TAG_GRM = 0x0100
|
TAG_GRM = 0x0100
|
||||||
TAG_NAME = 0x0200
|
TAG_NAME = 0x0200
|
||||||
@@ -123,12 +134,21 @@ def tagrepr(tag, w, size, off=None):
|
|||||||
return 'null%s%s' % (
|
return 'null%s%s' % (
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
' %d' % size if size else '')
|
' %d' % size if size else '')
|
||||||
elif tag == TAG_SUPERMAGIC:
|
elif (tag & 0xff00) == TAG_CONFIG:
|
||||||
return 'supermagic%s %d' % (
|
return '%s%s %d' % (
|
||||||
' w%d' % w if w else '',
|
'magic' if tag == TAG_MAGIC
|
||||||
size)
|
else 'version' if tag == TAG_VERSION
|
||||||
elif tag == TAG_SUPERCONFIG:
|
else 'flags' if tag == TAG_FLAGS
|
||||||
return 'superconfig%s %d' % (
|
else 'cksumtype' if tag == TAG_CKSUMTYPE
|
||||||
|
else 'redundtype' if tag == TAG_REDUNDTYPE
|
||||||
|
else 'blocklimit' if tag == TAG_BLOCKLIMIT
|
||||||
|
else 'disklimit' if tag == TAG_DISKLIMIT
|
||||||
|
else 'mleaflimit' if tag == TAG_MLEAFLIMIT
|
||||||
|
else 'sizelimit' if tag == TAG_SIZELIMIT
|
||||||
|
else 'namelimit' if tag == TAG_NAMELIMIT
|
||||||
|
else 'utaglimit' if tag == TAG_UTAGLIMIT
|
||||||
|
else 'uattrlimit' if tag == TAG_UATTRLIMIT
|
||||||
|
else 'config 0x%02x' % (tag & 0xff),
|
||||||
' w%d' % w if w else '',
|
' w%d' % w if w else '',
|
||||||
size)
|
size)
|
||||||
elif (tag & 0xff00) == TAG_GSTATE:
|
elif (tag & 0xff00) == TAG_GSTATE:
|
||||||
|
|||||||
Reference in New Issue
Block a user