mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 16:14:13 +01:00
Compare commits
2 Commits
test-revam
...
test-revam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1c0386bda | ||
|
|
4677421aba |
44
lfs.c
44
lfs.c
@@ -29,7 +29,8 @@ static int lfs_bd_read(lfs_t *lfs,
|
|||||||
lfs_block_t block, lfs_off_t off,
|
lfs_block_t block, lfs_off_t off,
|
||||||
void *buffer, lfs_size_t size) {
|
void *buffer, lfs_size_t size) {
|
||||||
uint8_t *data = buffer;
|
uint8_t *data = buffer;
|
||||||
if ((off+size > lfs->cfg->block_size) || (block == LFS_BLOCK_NULL)) {
|
if (block >= lfs->cfg->block_count ||
|
||||||
|
off+size > lfs->cfg->block_size) {
|
||||||
return LFS_ERR_CORRUPT;
|
return LFS_ERR_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +173,7 @@ static int lfs_bd_prog(lfs_t *lfs,
|
|||||||
lfs_block_t block, lfs_off_t off,
|
lfs_block_t block, lfs_off_t off,
|
||||||
const void *buffer, lfs_size_t size) {
|
const void *buffer, lfs_size_t size) {
|
||||||
const uint8_t *data = buffer;
|
const uint8_t *data = buffer;
|
||||||
LFS_ASSERT(block != LFS_BLOCK_NULL);
|
LFS_ASSERT(block == LFS_BLOCK_INLINE || block < lfs->cfg->block_count);
|
||||||
LFS_ASSERT(off + size <= lfs->cfg->block_size);
|
LFS_ASSERT(off + size <= lfs->cfg->block_size);
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
@@ -747,6 +748,12 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
|
|||||||
// scanning the entire directory
|
// scanning the entire directory
|
||||||
lfs_stag_t besttag = -1;
|
lfs_stag_t besttag = -1;
|
||||||
|
|
||||||
|
// if either block address is invalid we return LFS_ERR_CORRUPT here,
|
||||||
|
// otherwise later writes to the pair could fail
|
||||||
|
if (pair[0] >= lfs->cfg->block_count || pair[1] >= lfs->cfg->block_count) {
|
||||||
|
return LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
// find the block with the most recent revision
|
// find the block with the most recent revision
|
||||||
uint32_t revs[2] = {0, 0};
|
uint32_t revs[2] = {0, 0};
|
||||||
int r = 0;
|
int r = 0;
|
||||||
@@ -2196,7 +2203,6 @@ static int lfs_ctz_find(lfs_t *lfs,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT(head >= 2 && head <= lfs->cfg->block_count);
|
|
||||||
current -= 1 << skip;
|
current -= 1 << skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2216,7 +2222,6 @@ static int lfs_ctz_extend(lfs_t *lfs,
|
|||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
LFS_ASSERT(nblock >= 2 && nblock <= lfs->cfg->block_count);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
err = lfs_bd_erase(lfs, nblock);
|
err = lfs_bd_erase(lfs, nblock);
|
||||||
@@ -2289,8 +2294,6 @@ static int lfs_ctz_extend(lfs_t *lfs,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT(nhead >= 2 && nhead <= lfs->cfg->block_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*block = nblock;
|
*block = nblock;
|
||||||
@@ -3661,7 +3664,15 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
|
|
||||||
// scan directory blocks for superblock and any global updates
|
// scan directory blocks for superblock and any global updates
|
||||||
lfs_mdir_t dir = {.tail = {0, 1}};
|
lfs_mdir_t dir = {.tail = {0, 1}};
|
||||||
|
lfs_block_t cycle = 0;
|
||||||
while (!lfs_pair_isnull(dir.tail)) {
|
while (!lfs_pair_isnull(dir.tail)) {
|
||||||
|
if (cycle >= lfs->cfg->block_count/2) {
|
||||||
|
// loop detected
|
||||||
|
err = LFS_ERR_CORRUPT;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
cycle += 1;
|
||||||
|
|
||||||
// fetch next block in tail list
|
// fetch next block in tail list
|
||||||
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
|
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail,
|
||||||
LFS_MKTAG(0x7ff, 0x3ff, 0),
|
LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||||
@@ -3803,7 +3814,14 @@ int lfs_fs_traverseraw(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
lfs_block_t cycle = 0;
|
||||||
while (!lfs_pair_isnull(dir.tail)) {
|
while (!lfs_pair_isnull(dir.tail)) {
|
||||||
|
if (cycle >= lfs->cfg->block_count/2) {
|
||||||
|
// loop detected
|
||||||
|
return LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
cycle += 1;
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
int err = cb(data, dir.tail[i]);
|
int err = cb(data, dir.tail[i]);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -3887,7 +3905,14 @@ static int lfs_fs_pred(lfs_t *lfs,
|
|||||||
// iterate over all directory directory entries
|
// iterate over all directory directory entries
|
||||||
pdir->tail[0] = 0;
|
pdir->tail[0] = 0;
|
||||||
pdir->tail[1] = 1;
|
pdir->tail[1] = 1;
|
||||||
|
lfs_block_t cycle = 0;
|
||||||
while (!lfs_pair_isnull(pdir->tail)) {
|
while (!lfs_pair_isnull(pdir->tail)) {
|
||||||
|
if (cycle >= lfs->cfg->block_count/2) {
|
||||||
|
// loop detected
|
||||||
|
return LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
cycle += 1;
|
||||||
|
|
||||||
if (lfs_pair_cmp(pdir->tail, pair) == 0) {
|
if (lfs_pair_cmp(pdir->tail, pair) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3930,7 +3955,14 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
|||||||
// use fetchmatch with callback to find pairs
|
// use fetchmatch with callback to find pairs
|
||||||
parent->tail[0] = 0;
|
parent->tail[0] = 0;
|
||||||
parent->tail[1] = 1;
|
parent->tail[1] = 1;
|
||||||
|
lfs_block_t cycle = 0;
|
||||||
while (!lfs_pair_isnull(parent->tail)) {
|
while (!lfs_pair_isnull(parent->tail)) {
|
||||||
|
if (cycle >= lfs->cfg->block_count/2) {
|
||||||
|
// loop detected
|
||||||
|
return LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
cycle += 1;
|
||||||
|
|
||||||
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail,
|
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail,
|
||||||
LFS_MKTAG(0x7ff, 0, 0x3ff),
|
LFS_MKTAG(0x7ff, 0, 0x3ff),
|
||||||
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8),
|
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8),
|
||||||
|
|||||||
288
tests/test_evil.toml
Normal file
288
tests/test_evil.toml
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
# Tests for recovering from conditions which shouldn't normally
|
||||||
|
# happen during normal operation of littlefs
|
||||||
|
|
||||||
|
# invalid pointer tests (outside of block_count)
|
||||||
|
|
||||||
|
[[case]] # invalid tail-pointer test
|
||||||
|
define.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL']
|
||||||
|
define.INVALSET = [0x3, 0x1, 0x2]
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
|
||||||
|
// change tail-pointer to invalid pointers
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||||
|
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
|
||||||
|
(lfs_block_t[2]){
|
||||||
|
(INVALSET & 0x1) ? 0xcccccccc : 0,
|
||||||
|
(INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that mount fails gracefully
|
||||||
|
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # invalid dir pointer test
|
||||||
|
define.INVALSET = [0x3, 0x1, 0x2]
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
// make a dir
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_mkdir(&lfs, "dir_here") => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change the dir pointer to be invalid
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
// make sure id 1 == our directory
|
||||||
|
lfs_dir_get(&lfs, &mdir,
|
||||||
|
LFS_MKTAG(0x700, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer)
|
||||||
|
=> LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here"));
|
||||||
|
assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0);
|
||||||
|
// change dir pointer
|
||||||
|
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||||
|
{LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8),
|
||||||
|
(lfs_block_t[2]){
|
||||||
|
(INVALSET & 0x1) ? 0xcccccccc : 0,
|
||||||
|
(INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that accessing our bad dir fails, note there's a number
|
||||||
|
// of ways to access the dir, some can fail, but some don't
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_stat(&lfs, "dir_here", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "dir_here") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
|
||||||
|
lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT;
|
||||||
|
lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT;
|
||||||
|
lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT;
|
||||||
|
lfs_file_open(&lfs, &file, "dir_here/file_here",
|
||||||
|
LFS_O_RDONLY) => LFS_ERR_CORRUPT;
|
||||||
|
lfs_file_open(&lfs, &file, "dir_here/file_here",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # invalid file pointer test
|
||||||
|
in = "lfs.c"
|
||||||
|
define.SIZE = [10, 1000, 100000] # faked file size
|
||||||
|
code = '''
|
||||||
|
// create littlefs
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
// make a file
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "file_here",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change the file pointer to be invalid
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
// make sure id 1 == our file
|
||||||
|
lfs_dir_get(&lfs, &mdir,
|
||||||
|
LFS_MKTAG(0x700, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
|
||||||
|
=> LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here"));
|
||||||
|
assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
|
||||||
|
// change file pointer
|
||||||
|
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||||
|
{LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)),
|
||||||
|
&(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that accessing our bad file fails, note there's a number
|
||||||
|
// of ways to access the dir, some can fail, but some don't
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_stat(&lfs, "file_here", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "file_here") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == SIZE);
|
||||||
|
|
||||||
|
lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0;
|
||||||
|
lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT;
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
|
||||||
|
// any allocs that traverse CTZ must unfortunately must fail
|
||||||
|
if (SIZE > 2*LFS_BLOCK_SIZE) {
|
||||||
|
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # invalid pointer in CTZ skip-list test
|
||||||
|
define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE']
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
// make a file
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "file_here",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
||||||
|
for (int i = 0; i < SIZE; i++) {
|
||||||
|
char c = 'c';
|
||||||
|
lfs_file_write(&lfs, &file, &c, 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
// change pointer in CTZ skip-list to be invalid
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
// make sure id 1 == our file and get our CTZ structure
|
||||||
|
lfs_dir_get(&lfs, &mdir,
|
||||||
|
LFS_MKTAG(0x700, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
|
||||||
|
=> LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here"));
|
||||||
|
assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
|
||||||
|
struct lfs_ctz ctz;
|
||||||
|
lfs_dir_get(&lfs, &mdir,
|
||||||
|
LFS_MKTAG(0x700, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz)
|
||||||
|
=> LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz));
|
||||||
|
lfs_ctz_fromle32(&ctz);
|
||||||
|
// rewrite block to contain bad pointer
|
||||||
|
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||||
|
cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||||
|
uint32_t bad = lfs_tole32(0xcccccccc);
|
||||||
|
memcpy(&bbuffer[0], &bad, sizeof(bad));
|
||||||
|
memcpy(&bbuffer[4], &bad, sizeof(bad));
|
||||||
|
cfg.erase(&cfg, ctz.head) => 0;
|
||||||
|
cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that accessing our bad file fails, note there's a number
|
||||||
|
// of ways to access the dir, some can fail, but some don't
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_stat(&lfs, "file_here", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "file_here") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == SIZE);
|
||||||
|
|
||||||
|
lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0;
|
||||||
|
lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT;
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
|
||||||
|
// any allocs that traverse CTZ must unfortunately must fail
|
||||||
|
if (SIZE > 2*LFS_BLOCK_SIZE) {
|
||||||
|
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
|
||||||
|
}
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
[[case]] # invalid gstate pointer
|
||||||
|
define.INVALSET = [0x3, 0x1, 0x2]
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
|
||||||
|
// create an invalid gstate
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
|
||||||
|
(INVALSET & 0x1) ? 0xcccccccc : 0,
|
||||||
|
(INVALSET & 0x2) ? 0xcccccccc : 0});
|
||||||
|
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that mount fails gracefully
|
||||||
|
// mount may not fail, but our first alloc should fail when
|
||||||
|
// we try to fix the gstate
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
# cycle detection/recovery tests
|
||||||
|
|
||||||
|
[[case]] # metadata-pair threaded-list loop test
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
|
||||||
|
// change tail-pointer to point to ourself
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||||
|
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
|
||||||
|
(lfs_block_t[2]){0, 1}})) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that mount fails gracefully
|
||||||
|
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # metadata-pair threaded-list 2-length loop test
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs with child dir
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_mkdir(&lfs, "child") => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// find child
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_block_t pair[2];
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
lfs_dir_get(&lfs, &mdir,
|
||||||
|
LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
|
||||||
|
=> LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair));
|
||||||
|
lfs_pair_fromle32(pair);
|
||||||
|
// change tail-pointer to point to root
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, pair) => 0;
|
||||||
|
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||||
|
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
|
||||||
|
(lfs_block_t[2]){0, 1}})) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that mount fails gracefully
|
||||||
|
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # metadata-pair threaded-list 1-length child loop test
|
||||||
|
in = "lfs.c"
|
||||||
|
code = '''
|
||||||
|
// create littlefs with child dir
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_mkdir(&lfs, "child") => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// find child
|
||||||
|
lfs_init(&lfs, &cfg) => 0;
|
||||||
|
lfs_mdir_t mdir;
|
||||||
|
lfs_block_t pair[2];
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
|
||||||
|
lfs_dir_get(&lfs, &mdir,
|
||||||
|
LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
|
||||||
|
=> LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair));
|
||||||
|
lfs_pair_fromle32(pair);
|
||||||
|
// change tail-pointer to point to ourself
|
||||||
|
lfs_dir_fetch(&lfs, &mdir, pair) => 0;
|
||||||
|
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
|
||||||
|
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0;
|
||||||
|
lfs_deinit(&lfs) => 0;
|
||||||
|
|
||||||
|
// test that mount fails gracefully
|
||||||
|
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
|
||||||
|
'''
|
||||||
85
tests/test_new.toml
Normal file
85
tests/test_new.toml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
|
||||||
|
#open(1, "5file5.xxxxxxxxxxxx", 0x503) -> 0
|
||||||
|
# write(1, , 2007)[^ 1499 us] -> 2007
|
||||||
|
# write(1, , 2007)[^ 1411 us] -> 2007
|
||||||
|
# write(1, , 2007)[^ 1390 us] -> 2007
|
||||||
|
# write(1, , 2007)[^ 1401 us] -> 2007
|
||||||
|
# close(1) -> 0
|
||||||
|
# open(1, "1file1.xxxx", 0x503) -> 0
|
||||||
|
# mount
|
||||||
|
# open(0, "5file5.xxxxxxxxxxxx", 0x3) -> 0
|
||||||
|
# open(1, "5file5.xxxxxxxxxxxx", 0x503) -> 0
|
||||||
|
# close(1) -> 0
|
||||||
|
# open(1, "1file1.xxxx", 0x2) -> 0
|
||||||
|
# write(0, , 63) -> 63
|
||||||
|
#a.out: lfs.c:2169: lfs_ctz_find: Assertion `head >= 2 && head <= lfs->cfg->block_count' failed.
|
||||||
|
# close(0)Aborted
|
||||||
|
|
||||||
|
[[case]]
|
||||||
|
define.FILESIZE5 = '4*CHUNKSIZE5'
|
||||||
|
define.FILESIZE1 = '4*CHUNKSIZE1'
|
||||||
|
define.CHUNKSIZE5 = 2007
|
||||||
|
define.CHUNKSIZE1 = 63
|
||||||
|
code = '''
|
||||||
|
lfs_file_t files[2];
|
||||||
|
uint8_t chunk5[CHUNKSIZE5];
|
||||||
|
memset(chunk5, 'a', CHUNKSIZE5);
|
||||||
|
uint8_t chunk1[CHUNKSIZE1];
|
||||||
|
memset(chunk1, 'b', CHUNKSIZE1);
|
||||||
|
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &files[1], "5file5.xxxxxxxxxxxx",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
||||||
|
for (int i = 0; i < FILESIZE5/CHUNKSIZE5; i++) {
|
||||||
|
lfs_file_write(&lfs, &files[1], chunk5, CHUNKSIZE5) => CHUNKSIZE5;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &files[1]) => 0;
|
||||||
|
lfs_file_open(&lfs, &files[1], "1file1.xxxx",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
||||||
|
// these should not change the result
|
||||||
|
// lfs_file_close(&lfs, &files[1]) => 0;
|
||||||
|
// lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &files[0], "5file5.xxxxxxxxxxxx",
|
||||||
|
LFS_O_RDWR) => 0;
|
||||||
|
|
||||||
|
lfs_file_open(&lfs, &files[1], "5file5.xxxxxxxxxxxx",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
||||||
|
lfs_file_close(&lfs, &files[1]) => 0;
|
||||||
|
|
||||||
|
lfs_file_open(&lfs, &files[1], "1file1.xxxx",
|
||||||
|
LFS_O_WRONLY) => 0;
|
||||||
|
for (int i = 0; i < FILESIZE1/CHUNKSIZE1; i++) {
|
||||||
|
lfs_file_write(&lfs, &files[1], chunk1, CHUNKSIZE1) => CHUNKSIZE1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &files[1]) => 0;
|
||||||
|
|
||||||
|
memset(chunk5, 'c', CHUNKSIZE5);
|
||||||
|
for (int i = 0; i < FILESIZE5/CHUNKSIZE5; i++) {
|
||||||
|
lfs_file_write(&lfs, &files[0], chunk5, CHUNKSIZE5) => CHUNKSIZE5;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &files[0]) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// check results
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &files[0], "5file5.xxxxxxxxxxxx",
|
||||||
|
LFS_O_RDONLY) => 0;
|
||||||
|
for (int i = 0; i < FILESIZE5/CHUNKSIZE5; i++) {
|
||||||
|
uint8_t rchunk[CHUNKSIZE5];
|
||||||
|
lfs_file_read(&lfs, &files[0], rchunk, CHUNKSIZE5) => CHUNKSIZE5;
|
||||||
|
assert(memcmp(rchunk, chunk5, CHUNKSIZE5) == 0);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &files[0]) => 0;
|
||||||
|
lfs_file_open(&lfs, &files[0], "1file1.xxxx",
|
||||||
|
LFS_O_RDONLY) => 0;
|
||||||
|
for (int i = 0; i < FILESIZE1/CHUNKSIZE1; i++) {
|
||||||
|
uint8_t rchunk[CHUNKSIZE1];
|
||||||
|
lfs_file_read(&lfs, &files[0], rchunk, CHUNKSIZE1) => CHUNKSIZE1;
|
||||||
|
assert(memcmp(rchunk, chunk1, CHUNKSIZE1) == 0);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &files[0]) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
Reference in New Issue
Block a user