123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- # 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;
- '''
|