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:
Christopher Haster
2023-09-15 14:50:47 -05:00
parent 5f3994c83b
commit c1fe64314c
6 changed files with 715 additions and 391 deletions
+395 -279
View File
@@ -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,215 +6316,325 @@ 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;
}
// treat corrupted magic as no magic
if (lfs_cmp(cmp) != 0) {
err = LFS_ERR_NOENT;
}
} }
if (err == LFS_ERR_NOENT) { // treat corrupted magic as no magic
if (lfs_cmp(cmp) != 0) {
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) { if (err && err != LFS_ERR_CORRUPT) {
return err; return err;
} }
if (err == LFS_ERR_CORRUPT) {
if (err != LFS_ERR_CORRUPT) { utag_limit = -1;
err = lfsr_data_readleb128(lfs, &data, &minor_version);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
} }
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 return err;
}
if (err != LFS_ERR_NOENT) {
uint32_t uattr_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&uattr_limit);
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 || attr_limit != 0x7fffffff) { uattr_limit = -1;
LFS_ERROR("Incompatible attr limit 0x%"PRIx32
" (> 0x%"PRIx32")",
(err ? -1 : attr_limit),
0x7fffffff);
return LFS_ERR_INVAL;
} }
// check the on-disk name limit // only >=block_size uattrs are (implicitly) supported
// TODO actually use this if (uattr_limit < lfs->cfg->block_size-1) {
lfs_ssize_t name_limit; LFS_ERROR("Incompatible uattr limit "
err = lfsr_data_readleb128(lfs, &data, &name_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 || name_limit != 0xff) {
LFS_ERROR("Incompatible name limit 0x%"PRIx32
" (> 0x%"PRIx32")",
(err ? -1 : name_limit),
0xff);
return LFS_ERR_INVAL;
}
// check the on-disk file limit
// TODO actually use this
lfs_soff_t file_limit;
err = lfsr_data_readleb128(lfs, &data, &file_limit);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
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;
+21 -20
View File
@@ -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
View File
@@ -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:
+214 -67
View File
@@ -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
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
major, d_ = fromleb128(data[d:]); d += d_
minor, d_ = fromleb128(data[d:]); d += d_
return (major, minor)
else:
return (None, None)
@ft.cached_property
def flags(self):
if TAG_FLAGS in self.config:
_, data = self.config[TAG_FLAGS]
flags, _ = fromleb128(data)
return flags
else:
return None
@ft.cached_property
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
config = co.OrderedDict()
d = 0
def next(name):
nonlocal config, d
c, d_ = fromleb128(data[d:])
config[name] = (c, j, data[d:d+d_])
d += d_
next('major_version')
next('minor_version')
next('csum_type')
next('flags')
next('block_size')
next('block_count')
next('mlimit')
next('utag_limit')
next('attr_limit')
next('name_limit')
next('file_limit')
return config
# collect gstate # collect gstate
class GState: class GState:
@@ -695,25 +847,21 @@ class GState:
mid % self.mleaf_weight)) mid % self.mleaf_weight))
return rms return rms
def grepr(tag, data, mleaf_weight): def repr(self):
if tag == TAG_GRM: def grepr(tag, data):
d = 0 if tag == TAG_GRM:
count, d_ = fromleb128(data[d:]); d += d_ count, _ = fromleb128(data)
rms = [] return 'grm %s' % (
if count <= 2: 'none' if count == 0
for _ in range(count): else ' '.join('%d.%d' % (mbid//self.mleaf_weight, rid)
mid, d_ = fromleb128(data[d:]); d += d_ for mbid, rid in self.grm)
rms.append(( if count <= 2
mid - (mid % mleaf_weight), else '0x%x %d' % (count, len(data)))
mid % mleaf_weight)) else:
return 'grm %s' % ( return 'gstate 0x%02x %d' % (tag, len(data))
'none' if count == 0
else ' '.join('%d.%d' % (mbid//mleaf_weight, rid) for tag, data in sorted(self.gstate.items()):
for mbid, rid in rms) yield grepr(tag, data), tag, data
if count <= 2
else '0x%x' % count)
else:
return 'gstate 0x%02x %d' % (tag, len(data))
def frepr(mdir, rid, tag): def frepr(mdir, rid, tag):
if tag == TAG_BOOKMARK: if tag == TAG_BOOKMARK:
@@ -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
View File
@@ -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
View File
@@ -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: