bc9562c64e
- Off-by-one in test_btree_find_general[_sparse]_fuzz Because we can only create named btrees via splitting, these always start with one entry. If all operations are randomly selected to be splits, this can lead to an overflow of the sim buffer (sounds unlikely, but relatively easily for small N). The fix is to use a `for (lfs3_size_t i = 1; i < N; i++)` loop to account for the initial entry. Note we already use this in the test_btree_split_* tests. An alternative is allocating space for N+1 entries, but this seems unintuitive with N usually being associated with the upper bound on btree size. - Off-by-one in our sim rename pattern When renaming, we don't bother to update sim_size, because after the rename the sim_size size will be unchanged. But this means the sim_size is out-of-date during the memmove that reinserts the renamed entry. Buffer overflow! To fix we just need to use sim_size-1 to account for the temporarily deleted entry. This is messy C code, so not surprised it went unnoticed, even though this pattern ended up in quite a few tests. Found while running with HEAP=1. This was just intended to test HEAP=1, but I guess the injected heap hooks result in a more fragile heap? They increase all allocations by one word, and maybe this reduces alignment padding? Not exactly sure. But it's a good argument for maybe adding heap canaries in the future. Previously we ran Valgrind on all tests, but it's unclear if this will still be reasonable with the number of tests we have now.
11767 lines
388 KiB
TOML
11767 lines
388 KiB
TOML
# Test orphaned files and their various use cases
|
|
after = ['test_fwrite', 'test_fsync']
|
|
|
|
|
|
|
|
# test files don't exist until first sync/close
|
|
[cases.test_stickynotes_uncreat]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// check that the file doesn't _really_ exist
|
|
lfs3_t lfs3_;
|
|
lfs3_mount(&lfs3_, LFS3_M_RDONLY, CFG) => 0;
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3_, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// check that the file still doesn't _really_ exist
|
|
lfs3_mount(&lfs3_, LFS3_M_RDONLY, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_,
|
|
"batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
lfs3_mount(&lfs3_, LFS3_M_RDONLY, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3_, &file_) => 0;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
}
|
|
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
lfs3_mount(&lfs3_, LFS3_M_RDONLY, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3_, &file_) => 0;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
|
|
// should still be there
|
|
lfs3_mount(&lfs3_, LFS3_M_RDONLY, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3_, &file_) => 0;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
'''
|
|
|
|
|
|
# test files don't exist until first sync/close, even under powerloss
|
|
[cases.test_stickynotes_uncreat_pl]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs3_t lfs3;
|
|
int err = lfs3_mount(&lfs3, LFS3_M_RDWR, CFG);
|
|
if (err) {
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// create a file
|
|
//
|
|
// note the excl flag
|
|
lfs3_file_t file;
|
|
err = lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL);
|
|
assert(!err || err == LFS3_ERR_EXIST);
|
|
|
|
if (err != LFS3_ERR_EXIST) {
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// we should be able to read the file now
|
|
lfs3_file_open(&lfs3, &file, "batman", LFS3_O_RDONLY) => 0;
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// and after remounting
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
lfs3_file_open(&lfs3, &file, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test files don't exist until first sync/close, even under powerloss
|
|
[cases.test_stickynotes_uncreat_many_pl]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
]
|
|
defines.CHUNK = 8
|
|
defines.N = 128
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs3_t lfs3;
|
|
int err = lfs3_mount(&lfs3, LFS3_M_RDWR, CFG);
|
|
if (err) {
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// create N files
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
// note the excl flag
|
|
char name[256];
|
|
sprintf(name, "batman%03x", j);
|
|
lfs3_file_t file;
|
|
err = lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL);
|
|
assert(!err || err == LFS3_ERR_EXIST);
|
|
|
|
if (err != LFS3_ERR_EXIST) {
|
|
// write to the file
|
|
uint32_t prng = 42 + j;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// we should be able to read the files now
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", j);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
uint32_t prng = 42 + j;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// and after remounting
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", j);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
uint32_t prng = 42 + j;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test files only exist as stickynotes until first sync/close
|
|
[cases.test_stickynotes_uncreat_sync_wr]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// uncommitted files appear as stickynotes
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
// but we should still recieve sync broadcasts on sync/close
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_sync_rw]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
// open a second reference
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// uncommitted files appear as stickynotes
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// write to the second file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the second file
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_wdwr]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
// open a second reference
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
// and a third for checking sync broadcasts
|
|
lfs3_file_t file___;
|
|
lfs3_file_open(&lfs3, &file___, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// uncommitted files appear as stickynotes
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// uncommitted files appear as stickynotes
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the second file
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// now sync the first file, this should overwrite what is written
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// and close, this shouldn't change anything
|
|
//
|
|
// note we must sync to clear the desync flag
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file___) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_open]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the uncreat
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// our uncreat should have been overwritten
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_excl]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// attempt to create a new file over the uncreat
|
|
//
|
|
// this errors, otherwise it's easy to create the same file twice
|
|
// with excl, which would be super duper confusing for users
|
|
//
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => LFS3_ERR_EXIST;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the excl file had no effect
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_mkdir]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// attempt to mkdir
|
|
//
|
|
// this should fail because of the stickynote
|
|
//
|
|
lfs3_mkdir(&lfs3, "batman") => LFS3_ERR_EXIST;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the excl file had no effect
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test we can remove stickynotes
|
|
[cases.test_stickynotes_uncreat_rm]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// remove the stickynote
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// the stickynote should be gone
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "catman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test we can rename stickynotes
|
|
[cases.test_stickynotes_uncreat_mv]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename the stickynote
|
|
lfs3_rename(&lfs3, "batman", "catman") => 0;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the stickynote survived the rename
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "catman", &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "catman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test we can rename stickynotes onto files
|
|
[cases.test_stickynotes_uncreat_mv_replace]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreate
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// create another file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "catman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename the stickynote
|
|
lfs3_rename(&lfs3, "batman", "catman") => 0;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the stickynote survived the rename
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "catman", &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "catman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test we can rename stickynotes onto other files
|
|
[cases.test_stickynotes_uncreat_mv_src_file]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreate
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename the stickynote
|
|
lfs3_rename(&lfs3, "batman", "catman") => 0;
|
|
|
|
// we should still be able to read our uncreate/file
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, sizeof(rbuf))
|
|
=> strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the stickynote survived the rename
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "catman", &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "catman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test we can rename files onto stickynotes
|
|
[cases.test_stickynotes_uncreat_mv_dst_file]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreate
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename onto the stickynote
|
|
lfs3_rename(&lfs3, "catman", "batman") => 0;
|
|
|
|
// we should still be able to read our uncreate/file
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, sizeof(rbuf))
|
|
=> strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// test that the file replaced the stickynote
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test we can rename stickynotes onto other stickynotes
|
|
[cases.test_stickynotes_uncreat_mv_stickynote]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreate
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// create another uncreate
|
|
lfs3_file_t uncreat_;
|
|
lfs3_file_open(&lfs3, &uncreat_, "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat_, "WoO~", strlen("WoO~"))
|
|
=> strlen("WoO~");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename the stickynote
|
|
lfs3_rename(&lfs3, "batman", "catman") => 0;
|
|
|
|
// we should still be able to read our uncreates
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
lfs3_file_rewind(&lfs3, &uncreat_) => 0;
|
|
lfs3_file_read(&lfs3, &uncreat_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoO~");
|
|
assert(memcmp(rbuf, "WoO~", strlen("WoO~")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
lfs3_file_close(&lfs3, &uncreat_) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the stickynote survived the rename
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "catman", &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "catman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
lfs3_file_close(&lfs3, &uncreat_) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test renaming a stickynote onto itself does nothing
|
|
[cases.test_stickynotes_uncreat_mv_noop]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreate
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename the stickynote
|
|
lfs3_rename(&lfs3, "batman", "batman") => 0;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the stickynote survived the rename
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_not_dir]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// attempt to rename a dir onto the stickynote
|
|
//
|
|
// this should fail because of the stickynote
|
|
//
|
|
lfs3_mkdir(&lfs3, "datman") => 0;
|
|
lfs3_rename(&lfs3, "datman", "batman") => LFS3_ERR_NOTDIR;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the mkdir had no effect
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_stat(&lfs3, "datman", &info) => 0;
|
|
assert(strcmp(info.name, "datman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "datman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_not_stickynote]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// attempt to rename the stickynote onto a dir
|
|
//
|
|
// this should fail because of the stickynote
|
|
//
|
|
lfs3_mkdir(&lfs3, "datman") => 0;
|
|
lfs3_rename(&lfs3, "batman", "datman") => LFS3_ERR_ISDIR;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the mkdir had no effect
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_stat(&lfs3, "datman", &info) => 0;
|
|
assert(strcmp(info.name, "datman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "datman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_not_root]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// attempt to rename the stickynote onto the root
|
|
//
|
|
// this should fail because of the stickynote
|
|
//
|
|
// well, because of the root really, but also because of the
|
|
// stickynote
|
|
//
|
|
lfs3_rename(&lfs3, "batman", "/") => LFS3_ERR_BUSY;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the mkdir had no effect
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_uncreat_not_noent]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// attempt to rename the stickynote onto an invalid path
|
|
//
|
|
// this should fail because of the stickynote
|
|
//
|
|
// well, because of the invalid path really, but also because of the
|
|
// stickynote
|
|
//
|
|
lfs3_rename(&lfs3, "batman", "no/batman") => LFS3_ERR_NOENT;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the mkdir had no effect
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (CLOSE == 1) {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("WoOoOoOoOoO"));
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
if (CLOSE == 1) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
# test desync files don't exist until first sync + close
|
|
[cases.test_stickynotes_undesync]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// check that the file doesn't _really_ exist
|
|
lfs3_t lfs3_;
|
|
lfs3_mount(&lfs3_, LFS3_M_RDWR, CFG) => 0;
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3_, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// check that the file still doesn't _really_ exist
|
|
lfs3_mount(&lfs3_, LFS3_M_RDWR, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_,
|
|
"batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
lfs3_mount(&lfs3_, LFS3_M_RDWR, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3_, &file_) => 0;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
}
|
|
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
lfs3_mount(&lfs3_, LFS3_M_RDWR, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3_, &file_) => 0;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
|
|
// should still be there
|
|
lfs3_mount(&lfs3_, LFS3_M_RDWR, CFG) => 0;
|
|
// via stat
|
|
lfs3_stat(&lfs3_, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3_, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3_, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3_, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3_, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3_, &file_) => 0;
|
|
lfs3_unmount(&lfs3_) => 0;
|
|
'''
|
|
|
|
# test desync files don't exist until first sync + close, even under powerloss
|
|
[cases.test_stickynotes_undesync_pl]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs3_t lfs3;
|
|
int err = lfs3_mount(&lfs3, LFS3_M_RDWR, CFG);
|
|
if (err) {
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// create a desync file
|
|
//
|
|
// note the excl flag
|
|
lfs3_file_t file;
|
|
err = lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC);
|
|
assert(!err || err == LFS3_ERR_EXIST);
|
|
|
|
if (err != LFS3_ERR_EXIST) {
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// we should be able to read the file now
|
|
lfs3_file_open(&lfs3, &file, "batman", LFS3_O_RDONLY) => 0;
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// and after remounting
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
lfs3_file_open(&lfs3, &file, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test desync files don't exist until first sync + close, even under powerloss
|
|
[cases.test_stickynotes_undesync_many_pl]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
]
|
|
defines.CHUNK = 8
|
|
defines.N = 128
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs3_t lfs3;
|
|
int err = lfs3_mount(&lfs3, LFS3_M_RDWR, CFG);
|
|
if (err) {
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// create N desync files
|
|
lfs3_file_t files[N];
|
|
bool exists[N];
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
// note the excl flag
|
|
char name[256];
|
|
sprintf(name, "batman%03x", j);
|
|
err = lfs3_file_open(&lfs3, &files[j], name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC);
|
|
assert(!err || err == LFS3_ERR_EXIST);
|
|
|
|
exists[j] = (err == LFS3_ERR_EXIST);
|
|
if (!exists[j]) {
|
|
// write to the file
|
|
uint32_t prng = 42 + j;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[j], wbuf, CHUNK) => CHUNK;
|
|
}
|
|
}
|
|
}
|
|
// sync and close
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
if (!exists[j]) {
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &files[j]) => 0;
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &files[j]) => 0;
|
|
}
|
|
}
|
|
|
|
// we should be able to read the files now
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", j);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
uint32_t prng = 42 + j;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// and after remounting
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
for (lfs3_size_t j = 0; j < N; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", j);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
uint32_t prng = 42 + j;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test desync files aren't even openable until first sync + close
|
|
[cases.test_stickynotes_undesync_sync_wr]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_,
|
|
"batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_,
|
|
"batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
}
|
|
|
|
// but we should still recieve sync broadcasts on sync + close
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// sync the file
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// close the file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_undesync_sync_rw]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
// open a second desync reference
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_DESYNC) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// uncommitted files appear as stickynotes
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// write to the second file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
// close the second file
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_undesync_wdwr]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
// open a second desync reference
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
// and a third for checking sync broadcasts
|
|
lfs3_file_t file___;
|
|
lfs3_file_open(&lfs3, &file___, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
// close the second file
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// now sync the first file, this should overwrite what is written
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// and close, this shouldn't change anything
|
|
//
|
|
// note we must sync to clear the desync flag
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file___) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_undesync_open]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desynced uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the uncreat
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_undesync_excl]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
defines.CLOSE = [0, 1]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
defines.REMOUNT = [0, 1]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desynced uncreat
|
|
lfs3_file_t uncreat;
|
|
lfs3_file_open(&lfs3, &uncreat, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &uncreat,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the uncreat
|
|
//
|
|
// while it's still possible for the desynced uncreat to create the
|
|
// file by explicitly calling lfs3_file_sync, for the most part we
|
|
// treat desynced files like zombies and allow excl creates
|
|
//
|
|
// this makes lfs3_file_sync/resync roughly the same as opening the
|
|
// file after the excl create succeeds, and if you're using desynced
|
|
// files you should probably be aware of littlefs's snapshot model
|
|
// anyways
|
|
//
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// we should still be able to read our uncreat
|
|
lfs3_file_rewind(&lfs3, &uncreat) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &uncreat, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &uncreat) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# test that desynced, and then closed, files don't show up
|
|
[cases.test_stickynotes_orphan]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_,
|
|
"batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_,
|
|
"batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// because the file was desynced, it should still not exist
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// even after a remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// because the file was desynced, it should still not exist
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_wdwr]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
# SYNC=0x1 => sync before orphaning
|
|
# SYNC=0x2 => sync after orphaning
|
|
defines.SYNC = [0, 1, 2, 3]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
// open a second reference
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
// and a third for checking sync broadcasts
|
|
lfs3_file_t file___;
|
|
lfs3_file_open(&lfs3, &file___, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT) => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (SYNC & 0x1) {
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the first file, this should do nothing but discard the
|
|
// file contents
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (SYNC & 0x2) {
|
|
// sync the second file
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the second file
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file___) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_unrelated]
|
|
# different number of orphan require different methods of cleanup
|
|
defines.N = 'range(6)'
|
|
defines.M = 'range(6)'
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create N orphans
|
|
lfs3_file_t orphans[N];
|
|
for (lfs3_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", o);
|
|
lfs3_file_open(&lfs3, &orphans[o], name,
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
uint32_t prng = 42+o;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &orphans[o], wbuf, CHUNK) => CHUNK;
|
|
}
|
|
}
|
|
|
|
// and an unrelated file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
uint32_t prng = 52;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, none of the orphans exist
|
|
// via stat
|
|
struct lfs3_info info;
|
|
for (lfs3_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", o);
|
|
lfs3_stat(&lfs3, name, &info) => LFS3_ERR_NOENT;
|
|
}
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
uint8_t rbuf[CHUNK];
|
|
for (lfs3_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", o);
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, name, LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, name, LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, name, LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
}
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// but we should still be able to read our orphans
|
|
for (lfs3_size_t o = 0; o < N; o++) {
|
|
lfs3_file_rewind(&lfs3, &orphans[o]) => 0;
|
|
prng = 42+o;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &orphans[o], rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 52;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close M orphans
|
|
for (lfs3_size_t o = 0; o < M && o < N; o++) {
|
|
lfs3_file_close(&lfs3, &orphans[o]) => 0;
|
|
}
|
|
|
|
// create a new unrelated file, this should trigger
|
|
// and orphan cleanup
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
prng = 62;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
lfs3_file_close(&lfs3, &file__);
|
|
|
|
// and now close our original unrelated file
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// and close the remaining orphans
|
|
for (lfs3_size_t o = M; o < N; o++) {
|
|
lfs3_file_close(&lfs3, &orphans[o]) => 0;
|
|
}
|
|
|
|
// now our file should exist, but none of our orphans
|
|
// via stat
|
|
for (lfs3_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", o);
|
|
lfs3_stat(&lfs3, name, &info) => LFS3_ERR_NOENT;
|
|
}
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, "catman", &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "catman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
for (lfs3_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", o);
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, name, LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, name, LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, name, LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
}
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 52;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
lfs3_file_open(&lfs3, &file_, "catman", LFS3_O_RDONLY) => 0;
|
|
prng = 62;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_open]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfs3_file_t orphans[ORPHANS-1];
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", i);
|
|
lfs3_file_open(&lfs3, &orphans[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfs3_file_close(&lfs3, &orphans[i]) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the orphan
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_excl]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfs3_file_t orphans[ORPHANS-1];
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", i);
|
|
lfs3_file_open(&lfs3, &orphans[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfs3_file_close(&lfs3, &orphans[i]) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the zombie
|
|
//
|
|
// orphaned files will never exist again, so LFS3_O_EXCL should not
|
|
// fail here
|
|
//
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_mkdir]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfs3_file_t orphans[ORPHANS-1];
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", i);
|
|
lfs3_file_open(&lfs3, &orphans[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfs3_file_close(&lfs3, &orphans[i]) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new dir over the orphan
|
|
lfs3_mkdir(&lfs3, "batman") => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new dir is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_rm]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfs3_file_t orphans[ORPHANS-1];
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", i);
|
|
lfs3_file_open(&lfs3, &orphans[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfs3_file_close(&lfs3, &orphans[i]) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// orphans aren't real, so remove should fail
|
|
lfs3_remove(&lfs3, "batman") => LFS3_ERR_NOENT;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_mv_dst]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// make our src file before orphans, otherwise open just cleans
|
|
// things up
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "a/datman" : "datman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/datman" : "datman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfs3_file_t orphans[ORPHANS-1];
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "c/aatman%03x" : "aatman%03x", i);
|
|
lfs3_file_open(&lfs3, &orphans[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfs3_file_close(&lfs3, &orphans[i]) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename onto orphan
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "a/datman" : "datman",
|
|
(INTERDIR) ? "c/batman" : "batman") => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "c" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "c/batman" : "batman",
|
|
LFS3_O_RDONLY) => LFS3_ERR_ISDIR;
|
|
} else {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "c/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_orphan_mv_src]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfs3_file_t orphans[ORPHANS-1];
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "aatman%03x", i);
|
|
lfs3_file_open(&lfs3, &orphans[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs3_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfs3_file_close(&lfs3, &orphans[i]) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// orphans aren't real, so rename should fail
|
|
lfs3_rename(&lfs3, "batman", "catman") => LFS3_ERR_NOENT;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
lfs3_stat(&lfs3, "catman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# test that removed files never show up
|
|
[cases.test_stickynotes_zombie]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// syncing removed files is a noop
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// resyncing removed files is an error
|
|
lfs3_file_resync(&lfs3, &file) => LFS3_ERR_NOENT;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// because the file was removed, it should still not exist
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// even after a remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_posthumous]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// syncing removed files is a noop
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// resyncing removed files is an error
|
|
lfs3_file_resync(&lfs3, &file) => LFS3_ERR_NOENT;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// because the file was removed, it should still not exist
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// even after a remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_rwrw]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// as far as the filesystem is concerned, this file does not exist anymore
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// create a second file
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// syncing removed files is a noop
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// resyncing removed files is an error
|
|
lfs3_file_resync(&lfs3, &file) => LFS3_ERR_NOENT;
|
|
// syncing our second file should actually sync
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// second file should appear on disk now
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read both file handles
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_rwrw_posthumous]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// as far as the filesystem is concerned, this file does not exist anymore
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// create a second file
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the second file
|
|
uint32_t prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the first file
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// syncing removed files is a noop
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
// resyncing removed files is an error
|
|
lfs3_file_resync(&lfs3, &file) => LFS3_ERR_NOENT;
|
|
// syncing our second file should actually sync
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// second file should appear on disk now
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read both file handles
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_zombie_rwrwrw]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// as far as the filesystem is concerned, this file does not exist anymore
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// create a second file
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// still doesn't exist
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// create a third file
|
|
lfs3_file_t file___;
|
|
lfs3_file_open(&lfs3, &file___, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the third file
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file___, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// syncing removed files is a noop
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
// resyncing removed files is an error
|
|
lfs3_file_resync(&lfs3, &file) => LFS3_ERR_NOENT;
|
|
lfs3_file_resync(&lfs3, &file__) => LFS3_ERR_NOENT;
|
|
// syncing our third file should actually sync
|
|
lfs3_file_sync(&lfs3, &file___) => 0;
|
|
|
|
// third file should appear on disk now
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read all file handles
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
lfs3_file_close(&lfs3, &file___) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_zombie_rwrwrw_posthumous]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// as far as the filesystem is concerned, this file does not exist anymore
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// create a second file
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// still doesn't exist
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// rdonly rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => LFS3_ERR_NOENT;
|
|
// non-create rejected
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_WRONLY) => LFS3_ERR_NOENT;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDWR) => LFS3_ERR_NOENT;
|
|
|
|
// create a third file
|
|
lfs3_file_t file___;
|
|
lfs3_file_open(&lfs3, &file___, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the third file
|
|
uint32_t prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file___, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the first file
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// still appears as a stickynote
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// syncing removed files is a noop
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
// resyncing removed files is an error
|
|
lfs3_file_resync(&lfs3, &file) => LFS3_ERR_NOENT;
|
|
lfs3_file_resync(&lfs3, &file__) => LFS3_ERR_NOENT;
|
|
// syncing our third file should actually sync
|
|
lfs3_file_sync(&lfs3, &file___) => 0;
|
|
|
|
// third file should appear on disk now
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read all file handles
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file___) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
lfs3_file_close(&lfs3, &file___) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_open]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the zombie
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_excl]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new file over the zombie
|
|
//
|
|
// zombie files will never exist again, so LFS3_O_EXCL should not
|
|
// fail here
|
|
//
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "batman", LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_mkdir]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// create a new dir over the zombie
|
|
lfs3_mkdir(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new dir is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_rm]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// zombies aren't real, so remove should fail
|
|
lfs3_remove(&lfs3, "batman") => LFS3_ERR_NOENT;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_mv_dst]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// make our src file before zombies, just in case
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "c/datman" : "datman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, (INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename onto zombie
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => LFS3_ERR_ISDIR;
|
|
} else {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombie_mv_src]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// zombies aren't real, so rename should fail
|
|
lfs3_rename(&lfs3, "batman", "catman") => LFS3_ERR_NOENT;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
lfs3_stat(&lfs3, "catman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# test some other operations that can make zombies
|
|
[cases.test_stickynotes_zombify_mkdir]
|
|
defines.POSTHUMOUS = [false, true]
|
|
defines.CLOSE = [false, true]
|
|
defines.REMOUNT = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a desync file, not a zombie yet
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// use mkdir on the same name, the file hasn't been created yet,
|
|
// so this shouldn't fail, but because we have an open file handle
|
|
// we create a zombie
|
|
lfs3_mkdir(&lfs3, "batman") => 0;
|
|
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new dir is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
if (!CLOSE) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_zombify_mv_dst]
|
|
defines.ORPHAN = [false, true]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.POSTHUMOUS = [false, true]
|
|
defines.CLOSE = [false, true]
|
|
defines.REMOUNT = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = [
|
|
'REMOUNT <= CLOSE',
|
|
'!DIR || ORPHAN',
|
|
]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// make our src file before zombies, just in case
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "c/datman" : "datman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a desync file, not a zombie yet
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
if (!ORPHAN) {
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
}
|
|
|
|
// rename onto the same name, this shouldn't fail (note the test
|
|
// conditions), but because we have an open file handle we create
|
|
// a zombie
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => LFS3_ERR_ISDIR;
|
|
} else {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (!CLOSE) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_fileonzombie_rm]
|
|
defines.DIR = [false, true]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
// create a file on top of the zombie
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, "batman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "batman") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman", &info) => LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_fileonzombie_mv_dst]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// make our src file before zombies, just in case
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "c/datman" : "datman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, (INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
// create a file on top of the zombie
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "a/batman" : "batman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename onto the file
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => LFS3_ERR_ISDIR;
|
|
} else {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# test that we actually cleanup orphans correctly
|
|
[cases.test_stickynotes_cleanup]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
# <=2 => grm-able
|
|
# >2 => requires orphans
|
|
defines.N = [0, 1, 2, 3, 10, 100]
|
|
defines.REMOUNT = [false, true]
|
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
|
in = 'lfs3.c'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint32_t prng = 42;
|
|
|
|
// create some unrelated files to make sure cleaning up orphans
|
|
// doesn't break other filesystem things
|
|
uint32_t bookend_prngs[2] = {0, 0};
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "aatman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "catman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create this many orphaned files
|
|
//
|
|
// anytime we close a not-yet-created desync file, we create an
|
|
// orphan, but note we need these to be different files, and we need
|
|
// to close them after all open calls, otherwise we just end up with
|
|
// one orphan (littlefs is eager to clean up orphans)
|
|
//
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// remount? this has no effect on orphans
|
|
if (REMOUNT) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// calling lfs3_fs_mkconsistent should clean things up
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
|
|
// we should have cleaned up all grms/orphans
|
|
assert(lfs3.grm.queue[0] == 0);
|
|
assert(lfs3.grm.queue[1] == 0);
|
|
assert(!(lfs3.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
struct lfs3_fsinfo fsinfo;
|
|
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
|
assert(!(fsinfo.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
// double check the actual disk state, it's easy for littlefs to
|
|
// lie here
|
|
assert(lfs3_mtree_weight(&lfs3)
|
|
<= ((1+lfs3_popc(BOOKENDS)) << lfs3.mbits));
|
|
lfs3_mdir_t mdir;
|
|
lfs3_mtree_lookup(&lfs3, 0, &mdir) => 0;
|
|
assert(mdir.r.weight <= 1+lfs3_popc(BOOKENDS));
|
|
|
|
// check that other files are unaffected
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "aatman", LFS3_O_RDONLY) => 0;
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file);
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "catman", LFS3_O_RDONLY) => 0;
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file);
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_cleanup_open]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
# <=2 => grm-able
|
|
# >2 => requires orphans
|
|
defines.N = [0, 1, 2, 3, 10, 100]
|
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
|
in = 'lfs3.c'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint32_t prng = 42;
|
|
|
|
// create some unrelated opened files to make sure cleaning up
|
|
// orphans doesn't break other filesystem things
|
|
//
|
|
// note we leave these open in this test
|
|
lfs3_file_t bookend_files[2];
|
|
uint32_t bookend_prngs[2] = {0, 0};
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_open(&lfs3, &bookend_files[0], "aatman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &bookend_files[0], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &bookend_files[0]) => 0;
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_open(&lfs3, &bookend_files[1], "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &bookend_files[1], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &bookend_files[1]) => 0;
|
|
}
|
|
|
|
// create this many orphaned files
|
|
//
|
|
// anytime we close a not-yet-created desync file, we create an
|
|
// orphan, but note we need these to be different files, and we need
|
|
// to close them after all open calls, otherwise we just end up with
|
|
// one orphan (littlefs is eager to clean up orphans)
|
|
//
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// calling lfs3_fs_mkconsistent should clean things up
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
|
|
// we should have cleaned up all grms/orphans
|
|
assert(lfs3.grm.queue[0] == 0);
|
|
assert(lfs3.grm.queue[1] == 0);
|
|
assert(!(lfs3.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
struct lfs3_fsinfo fsinfo;
|
|
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
|
assert(!(fsinfo.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
// double check the actual disk state, it's easy for littlefs to
|
|
// lie here
|
|
assert(lfs3_mtree_weight(&lfs3)
|
|
<= ((1+lfs3_popc(BOOKENDS)) << lfs3.mbits));
|
|
lfs3_mdir_t mdir;
|
|
lfs3_mtree_lookup(&lfs3, 0, &mdir) => 0;
|
|
assert(mdir.r.weight <= 1+lfs3_popc(BOOKENDS));
|
|
|
|
// check that other files are unaffected
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
if (remount) {
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_close(&lfs3, &bookend_files[0]) => 0;
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_close(&lfs3, &bookend_files[1]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_open(&lfs3, &bookend_files[0], "aatman",
|
|
LFS3_O_RDONLY) => 0;
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_open(&lfs3, &bookend_files[1], "catman",
|
|
LFS3_O_RDONLY) => 0;
|
|
}
|
|
}
|
|
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_rewind(&lfs3, &bookend_files[0]) => 0;
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &bookend_files[0], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_rewind(&lfs3, &bookend_files[1]) => 0;
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &bookend_files[1], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_close(&lfs3, &bookend_files[0]);
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_close(&lfs3, &bookend_files[1]);
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_cleanup_uncreat]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
# <=2 => grm-able
|
|
# >2 => requires orphans
|
|
defines.N = [0, 1, 2, 3, 10, 100]
|
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
|
in = 'lfs3.c'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint32_t prng = 42;
|
|
|
|
// create some unrelated uncreat files to make sure cleaning up
|
|
// orphans doesn't break other filesystem things
|
|
//
|
|
// note we leave these uncreated + open in this test
|
|
lfs3_file_t bookend_files[2];
|
|
uint32_t bookend_prngs[2] = {0, 0};
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_open(&lfs3, &bookend_files[0], "aatman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &bookend_files[0], wbuf, SIZE) => SIZE;
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_open(&lfs3, &bookend_files[1], "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &bookend_files[1], wbuf, SIZE) => SIZE;
|
|
}
|
|
|
|
// create this many orphaned files
|
|
//
|
|
// anytime we close a not-yet-created desync file, we create an
|
|
// orphan, but note we need these to be different files, and we need
|
|
// to close them after all open calls, otherwise we just end up with
|
|
// one orphan (littlefs is eager to clean up orphans)
|
|
//
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// calling lfs3_fs_mkconsistent should clean things up
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
|
|
// we should have cleaned up all grms/orphans
|
|
assert(lfs3.grm.queue[0] == 0);
|
|
assert(lfs3.grm.queue[1] == 0);
|
|
assert(!(lfs3.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
struct lfs3_fsinfo fsinfo;
|
|
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
|
assert(!(fsinfo.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
// double check the actual disk state, it's easy for littlefs to
|
|
// lie here
|
|
assert(lfs3_mtree_weight(&lfs3)
|
|
<= ((1+lfs3_popc(BOOKENDS)) << lfs3.mbits));
|
|
lfs3_mdir_t mdir;
|
|
lfs3_mtree_lookup(&lfs3, 0, &mdir) => 0;
|
|
assert(mdir.r.weight <= 1+lfs3_popc(BOOKENDS));
|
|
|
|
// check that other files are unaffected
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
if (remount) {
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_close(&lfs3, &bookend_files[0]) => 0;
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_close(&lfs3, &bookend_files[1]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_open(&lfs3, &bookend_files[0], "aatman",
|
|
LFS3_O_RDONLY) => 0;
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_open(&lfs3, &bookend_files[1], "catman",
|
|
LFS3_O_RDONLY) => 0;
|
|
}
|
|
}
|
|
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_rewind(&lfs3, &bookend_files[0]) => 0;
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &bookend_files[0], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_rewind(&lfs3, &bookend_files[1]) => 0;
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &bookend_files[1], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_close(&lfs3, &bookend_files[0]);
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_close(&lfs3, &bookend_files[1]);
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_cleanup_zombie]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
# <=2 => grm-able
|
|
# >2 => requires orphans
|
|
defines.N = [0, 1, 2, 3, 10, 100]
|
|
defines.BOOKENDS = [0x0, 0x1, 0x2, 0x3]
|
|
if = '(SIZE*N)/BLOCK_SIZE <= 32'
|
|
in = 'lfs3.c'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint32_t prng = 42;
|
|
|
|
// create some unrelated zombie files to make sure cleaning up
|
|
// orphans doesn't break other filesystem things
|
|
//
|
|
// note we leave these zombied + open in this test
|
|
lfs3_file_t bookend_files[2];
|
|
uint32_t bookend_prngs[2] = {0, 0};
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_open(&lfs3, &bookend_files[0], "aatman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[0] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &bookend_files[0], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &bookend_files[0]) => 0;
|
|
|
|
lfs3_remove(&lfs3, "aatman") => 0;
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_open(&lfs3, &bookend_files[1], "catman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
bookend_prngs[1] = TEST_PRNG(&prng);
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &bookend_files[1], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &bookend_files[1]) => 0;
|
|
|
|
lfs3_remove(&lfs3, "catman") => 0;
|
|
}
|
|
|
|
// create this many orphaned files
|
|
//
|
|
// anytime we close a not-yet-created desync file, we create an
|
|
// orphan, but note we need these to be different files, and we need
|
|
// to close them after all open calls, otherwise we just end up with
|
|
// one orphan (littlefs is eager to clean up orphans)
|
|
//
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], name,
|
|
LFS3_O_WRONLY
|
|
| LFS3_O_CREAT
|
|
| LFS3_O_EXCL
|
|
| LFS3_O_DESYNC) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// calling lfs3_fs_mkconsistent should clean things up
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
|
|
// we should have cleaned up all grms/orphans
|
|
assert(lfs3.grm.queue[0] == 0);
|
|
assert(lfs3.grm.queue[1] == 0);
|
|
assert(!(lfs3.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
struct lfs3_fsinfo fsinfo;
|
|
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
|
assert(!(fsinfo.flags & LFS3_I_MKCONSISTENT));
|
|
|
|
// double check the actual disk state, it's easy for littlefs to
|
|
// lie here
|
|
assert(lfs3_mtree_weight(&lfs3)
|
|
<= ((1+lfs3_popc(BOOKENDS)) << lfs3.mbits));
|
|
lfs3_mdir_t mdir;
|
|
lfs3_mtree_lookup(&lfs3, 0, &mdir) => 0;
|
|
assert(mdir.r.weight <= 1+lfs3_popc(BOOKENDS));
|
|
|
|
// check that other files are unaffected
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_rewind(&lfs3, &bookend_files[0]) => 0;
|
|
uint32_t prng_ = bookend_prngs[0];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &bookend_files[0], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_rewind(&lfs3, &bookend_files[1]) => 0;
|
|
uint32_t prng_ = bookend_prngs[1];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
|
}
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &bookend_files[1], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
if (BOOKENDS & 0x1) {
|
|
lfs3_file_close(&lfs3, &bookend_files[0]);
|
|
}
|
|
if (BOOKENDS & 0x2) {
|
|
lfs3_file_close(&lfs3, &bookend_files[1]);
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# test that file handles follow mvs correctly
|
|
#
|
|
# these doesn't really involve stickynotes, but it's the same internal
|
|
# circuitry, we might as well test them here
|
|
#
|
|
[cases.test_stickynotes_file_mv]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can rename
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// rename the file
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// the file should have been renamed
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// close should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_file_mv_postmv]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// need to sync so we can rename
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// rename the file
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// the file should have been renamed, but zero sized
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// the data should now be visible
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// we should still be able to read our file handle
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// the data should now be visible
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_file_mv_file_rwrw]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can rename
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// create a second file
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_TRUNC) => 0;
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// rename the file
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// the file should have been renamed
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// but we should still be able to read both file handles
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync, note the order
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// the second file's data should now be visible
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// both file handles should be updated
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close, note the order
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// close should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_file_mv_rwrw_postmv]
|
|
defines.SIZE = [
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'LFS3_MIN(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
defines.MKCONSISTENT = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
|
|
// need to sync so we can rename
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// create a second file
|
|
lfs3_file_t file__;
|
|
lfs3_file_open(&lfs3, &file__, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_TRUNC) => 0;
|
|
|
|
// rename the file
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// mkconsistent should have no effect
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// the file should have been renamed, but zero sized
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => 0;
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// but we should still be able to read both file handles
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync, note the order
|
|
lfs3_file_sync(&lfs3, &file__) => 0;
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// the second file's data should now be visible
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// both file handles should be updated
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close, note the order
|
|
lfs3_file_close(&lfs3, &file__) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// close should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// remount
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs3_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs3_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_file_mv_mv_src]
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.POSTMV = [false, true]
|
|
defines.SYNC = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
if (!POSTMV) {
|
|
lfs3_file_write(&lfs3, &file,
|
|
"catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
if (SYNC) {
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
}
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename while open
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTMV) {
|
|
lfs3_file_write(&lfs3, &file,
|
|
"catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
if (SYNC) {
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// we should still be able to read our file
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file, rbuf, sizeof(rbuf))
|
|
=> strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
if ((SYNC || CLOSE >= 1) && !(POSTMV && CLOSE >= 2)) {
|
|
assert(info.size == strlen("catman!"));
|
|
} else {
|
|
assert(info.size == 0);
|
|
}
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
if ((SYNC || CLOSE >= 1) && !(POSTMV && CLOSE >= 2)) {
|
|
assert(info.size == strlen("catman!"));
|
|
} else {
|
|
assert(info.size == 0);
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
if ((SYNC || CLOSE >= 1) && !(POSTMV && CLOSE >= 2)) {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_file_fileonzombie_mv_src]
|
|
defines.DIR = [false, true]
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.POSTHUMOUS = [false, true]
|
|
# CLOSE=0 => don't close (before end of test)
|
|
# CLOSE=1 => close after op
|
|
# CLOSE=2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# REMOUNT=0 => don't remount
|
|
# REMOUNT=1 => remount after op
|
|
# REMOUNT=2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.MKCONSISTENT = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfs3_mkdir(&lfs3, "a") => 0;
|
|
lfs3_mkdir(&lfs3, "b") => 0;
|
|
lfs3_mkdir(&lfs3, "c") => 0;
|
|
}
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/catman%03x" : "catman%03x", i);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "a/batman" : "batman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// create a zombie
|
|
lfs3_file_t zombie;
|
|
lfs3_file_open(&lfs3, &zombie, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfs3_file_sync(&lfs3, &zombie) => 0;
|
|
lfs3_remove(&lfs3, (INTERDIR) ? "c/datman" : "datman") => 0;
|
|
|
|
// create a file on top of the zombie
|
|
if (DIR) {
|
|
lfs3_mkdir(&lfs3, (INTERDIR) ? "c/datman" : "datman") => 0;
|
|
} else {
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, (INTERDIR) ? "c/datman" : "datman",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &file, "catman!", strlen("catman!"))
|
|
=> strlen("catman!");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// rename while open
|
|
lfs3_rename(&lfs3,
|
|
(INTERDIR) ? "c/datman" : "datman",
|
|
(INTERDIR) ? "a/batman" : "batman") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfs3_file_write(&lfs3, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our file
|
|
lfs3_file_rewind(&lfs3, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
}
|
|
if (MKCONSISTENT) {
|
|
lfs3_fs_mkconsistent(&lfs3) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "a/batman" : "batman", &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
lfs3_stat(&lfs3, (INTERDIR) ? "c/datman" : "datman", &info)
|
|
=> LFS3_ERR_NOENT;
|
|
// via readdir
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "batman") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == strlen("catman!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs3_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/catman%03x" : "catman%03x", i);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => LFS3_ERR_ISDIR;
|
|
} else {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, (INTERDIR) ? "a/batman" : "batman",
|
|
LFS3_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfs3_file_read(&lfs3, &file_, rbuf, sizeof(rbuf)) => strlen("catman!");
|
|
assert(memcmp(rbuf, "catman!", strlen("catman!")) == 0);
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
}
|
|
|
|
if (CLOSE == 0) {
|
|
lfs3_file_close(&lfs3, &zombie) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# one particularly nasty case is renaming over an mdir split, since shrubs
|
|
# can be moved around quite a few times when that happens
|
|
#
|
|
# here we spam renames over an increasing number of files to hopefully hit
|
|
# that case
|
|
#
|
|
[cases.test_stickynotes_file_mv_split]
|
|
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
|
defines.SIZE = [
|
|
'0',
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
# keep unsynced data open?
|
|
defines.UNSYNC = [false, true]
|
|
# keep a desynced file open?
|
|
defines.DESYNC = [false, true]
|
|
# keep a zombie open?
|
|
defines.ZOMBIE = [false, true]
|
|
if = '(SIZE*N*(1+DESYNC+ZOMBIE))/BLOCK_SIZE <= 32'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// we need a file handle for each file + desync + zombie
|
|
lfs3_file_t files[N];
|
|
lfs3_file_t desyncs[N];
|
|
lfs3_file_t zombies[N];
|
|
|
|
// create this many files while renaming
|
|
uint32_t prng = 42;
|
|
uint32_t unsync_prng = 43;
|
|
uint32_t desync_prng = 44;
|
|
uint32_t zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// create a zombie?
|
|
if (ZOMBIE) {
|
|
lfs3_file_open(&lfs3, &zombies[i], "batman!!!",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &zombies[i], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &zombies[i]) => 0;
|
|
lfs3_remove(&lfs3, "batman!!!") => 0;
|
|
}
|
|
|
|
// always create as first file
|
|
lfs3_file_open(&lfs3, &files[i], "batman!!!",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &files[i]) => 0;
|
|
|
|
// keep unsynced data?
|
|
if (UNSYNC) {
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&unsync_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
|
|
// keep a desynced file open?
|
|
if (DESYNC) {
|
|
lfs3_file_open(&lfs3, &desyncs[i], "batman!!!",
|
|
LFS3_O_RDWR | LFS3_O_DESYNC | LFS3_O_TRUNC) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &desyncs[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
|
|
// rename!
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_rename(&lfs3, "batman!!!", name) => 0;
|
|
}
|
|
|
|
// check that renames worked
|
|
prng = 42;
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman!!!", &info) => LFS3_ERR_NOENT;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check with stat
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
lfs3_file_t file;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that file handles are as expected
|
|
prng = (!UNSYNC) ? 42 : 43;
|
|
desync_prng = 44;
|
|
zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check size
|
|
assert(lfs3_file_size(&lfs3, &files[i]) == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
lfs3_file_read(&lfs3, &files[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// check any desynced files
|
|
if (DESYNC) {
|
|
assert(lfs3_file_size(&lfs3, &desyncs[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &desyncs[i]) => 0;
|
|
lfs3_file_read(&lfs3, &desyncs[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// check any zombied files
|
|
if (ZOMBIE) {
|
|
assert(lfs3_file_size(&lfs3, &zombies[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &zombies[i]) => 0;
|
|
lfs3_file_read(&lfs3, &zombies[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
// try syncing any unsynced files
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_sync(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// check that sync worked
|
|
prng = (!UNSYNC) ? 42 : 43;
|
|
lfs3_stat(&lfs3, "batman!!!", &info) => LFS3_ERR_NOENT;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check with stat
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
lfs3_file_t file;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that file handles are as expected
|
|
prng = (!UNSYNC) ? 42 : 43;
|
|
desync_prng = 44;
|
|
zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check size
|
|
assert(lfs3_file_size(&lfs3, &files[i]) == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
lfs3_file_read(&lfs3, &files[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// check any desynced files
|
|
if (DESYNC) {
|
|
assert(lfs3_file_size(&lfs3, &desyncs[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &desyncs[i]) => 0;
|
|
lfs3_file_read(&lfs3, &desyncs[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// check any zombied files
|
|
if (ZOMBIE) {
|
|
assert(lfs3_file_size(&lfs3, &zombies[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &zombies[i]) => 0;
|
|
lfs3_file_read(&lfs3, &zombies[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
// try rewriting our open files
|
|
uint32_t rewrite_prng = 52;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&rewrite_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// check that rewrites worked
|
|
rewrite_prng = 52;
|
|
lfs3_stat(&lfs3, "batman!!!", &info) => LFS3_ERR_NOENT;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check with stat
|
|
char name[256];
|
|
sprintf(name, "batman%03x", i);
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&rewrite_prng) % 26);
|
|
}
|
|
|
|
lfs3_file_t file;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that file handles are as expected
|
|
rewrite_prng = 52;
|
|
desync_prng = 44;
|
|
zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check size
|
|
assert(lfs3_file_size(&lfs3, &files[i]) == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&rewrite_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
lfs3_file_read(&lfs3, &files[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// check any desynced files
|
|
if (DESYNC) {
|
|
assert(lfs3_file_size(&lfs3, &desyncs[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &desyncs[i]) => 0;
|
|
lfs3_file_read(&lfs3, &desyncs[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// check any zombied files
|
|
if (ZOMBIE) {
|
|
assert(lfs3_file_size(&lfs3, &zombies[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &zombies[i]) => 0;
|
|
lfs3_file_read(&lfs3, &zombies[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
// cleanup files
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
if (DESYNC) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &desyncs[i]) => 0;
|
|
}
|
|
}
|
|
if (ZOMBIE) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &zombies[i]) => 0;
|
|
}
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
[cases.test_stickynotes_file_mv_split_backwards]
|
|
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
|
defines.SIZE = [
|
|
'0',
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
# keep unsynced data open?
|
|
defines.UNSYNC = [false, true]
|
|
# keep a desynced file open?
|
|
defines.DESYNC = [false, true]
|
|
# keep a zombie open?
|
|
defines.ZOMBIE = [false, true]
|
|
if = '(SIZE*N*(1+DESYNC+ZOMBIE))/BLOCK_SIZE <= 32'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// we need a file handle for each file + desync + zombie
|
|
lfs3_file_t files[N];
|
|
lfs3_file_t desyncs[N];
|
|
lfs3_file_t zombies[N];
|
|
|
|
// create this many files while renaming
|
|
uint32_t prng = 42;
|
|
uint32_t unsync_prng = 43;
|
|
uint32_t desync_prng = 44;
|
|
uint32_t zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// create a zombie?
|
|
if (ZOMBIE) {
|
|
lfs3_file_open(&lfs3, &zombies[i], "batman???",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &zombies[i], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &zombies[i]) => 0;
|
|
lfs3_remove(&lfs3, "batman???") => 0;
|
|
}
|
|
|
|
// always create as last file
|
|
lfs3_file_open(&lfs3, &files[i], "batman???",
|
|
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &files[i]) => 0;
|
|
|
|
// keep unsynced data?
|
|
if (UNSYNC) {
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&unsync_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
|
|
// keep a desynced file open?
|
|
if (DESYNC) {
|
|
lfs3_file_open(&lfs3, &desyncs[i], "batman???",
|
|
LFS3_O_RDWR | LFS3_O_DESYNC | LFS3_O_TRUNC) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &desyncs[i], wbuf, SIZE) => SIZE;
|
|
}
|
|
|
|
// rename!
|
|
char name[256];
|
|
sprintf(name, "batman%03x", (uint32_t)(N-1-i));
|
|
lfs3_rename(&lfs3, "batman???", name) => 0;
|
|
}
|
|
|
|
// check that renames worked
|
|
prng = 42;
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, "batman???", &info) => LFS3_ERR_NOENT;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check with stat
|
|
char name[256];
|
|
sprintf(name, "batman%03x", (uint32_t)(N-1-i));
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
lfs3_file_t file;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that file handles are as expected
|
|
prng = (!UNSYNC) ? 42 : 43;
|
|
desync_prng = 44;
|
|
zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check size
|
|
assert(lfs3_file_size(&lfs3, &files[i]) == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
lfs3_file_read(&lfs3, &files[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// check any desynced files
|
|
if (DESYNC) {
|
|
assert(lfs3_file_size(&lfs3, &desyncs[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &desyncs[i]) => 0;
|
|
lfs3_file_read(&lfs3, &desyncs[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// check any zombied files
|
|
if (ZOMBIE) {
|
|
assert(lfs3_file_size(&lfs3, &zombies[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &zombies[i]) => 0;
|
|
lfs3_file_read(&lfs3, &zombies[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
// try syncing any unsynced files
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_sync(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// check that sync worked
|
|
prng = (!UNSYNC) ? 42 : 43;
|
|
lfs3_stat(&lfs3, "batman???", &info) => LFS3_ERR_NOENT;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check with stat
|
|
char name[256];
|
|
sprintf(name, "batman%03x", (uint32_t)(N-1-i));
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
lfs3_file_t file;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that file handles are as expected
|
|
prng = (!UNSYNC) ? 42 : 43;
|
|
desync_prng = 44;
|
|
zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check size
|
|
assert(lfs3_file_size(&lfs3, &files[i]) == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
lfs3_file_read(&lfs3, &files[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// check any desynced files
|
|
if (DESYNC) {
|
|
assert(lfs3_file_size(&lfs3, &desyncs[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &desyncs[i]) => 0;
|
|
lfs3_file_read(&lfs3, &desyncs[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// check any zombied files
|
|
if (ZOMBIE) {
|
|
assert(lfs3_file_size(&lfs3, &zombies[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &zombies[i]) => 0;
|
|
lfs3_file_read(&lfs3, &zombies[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
// try rewriting our open files
|
|
uint32_t rewrite_prng = 52;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&rewrite_prng) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &files[i], wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &files[i]) => 0;
|
|
}
|
|
|
|
// check that rewrites worked
|
|
rewrite_prng = 52;
|
|
lfs3_stat(&lfs3, "batman???", &info) => LFS3_ERR_NOENT;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check with stat
|
|
char name[256];
|
|
sprintf(name, "batman%03x", (uint32_t)(N-1-i));
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&rewrite_prng) % 26);
|
|
}
|
|
|
|
lfs3_file_t file;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that file handles are as expected
|
|
rewrite_prng = 52;
|
|
desync_prng = 44;
|
|
zombie_prng = 45;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
// check size
|
|
assert(lfs3_file_size(&lfs3, &files[i]) == SIZE);
|
|
|
|
// try reading the file
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&rewrite_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &files[i]) => 0;
|
|
lfs3_file_read(&lfs3, &files[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// check any desynced files
|
|
if (DESYNC) {
|
|
assert(lfs3_file_size(&lfs3, &desyncs[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&desync_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &desyncs[i]) => 0;
|
|
lfs3_file_read(&lfs3, &desyncs[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// check any zombied files
|
|
if (ZOMBIE) {
|
|
assert(lfs3_file_size(&lfs3, &zombies[i]) == SIZE);
|
|
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&zombie_prng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_rewind(&lfs3, &zombies[i]) => 0;
|
|
lfs3_file_read(&lfs3, &zombies[i], rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
// cleanup files
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
if (DESYNC) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &desyncs[i]) => 0;
|
|
}
|
|
}
|
|
if (ZOMBIE) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &zombies[i]) => 0;
|
|
}
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
|
|
# fuzz tests involving many uncreats + zombies, this gets a bit crazy
|
|
[cases.test_stickynotes_uz_fuzz]
|
|
# you probably need to flush if you expect errors
|
|
defines.FLUSH = false
|
|
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
|
# do more ops than files to encourage file rewrites
|
|
defines.OPS = '2*N'
|
|
defines.SIZE = [
|
|
'0',
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
if = '(SIZE*N)/BLOCK_SIZE <= 16'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// set up a simulation to compare against
|
|
lfs3_size_t *sim = malloc(N*sizeof(lfs3_size_t));
|
|
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
|
|
bool *sim_isstickys = malloc(N*sizeof(bool));
|
|
lfs3_size_t sim_size = 0;
|
|
|
|
typedef struct sim_file {
|
|
lfs3_size_t x;
|
|
bool sticky;
|
|
bool zombie;
|
|
uint32_t prng;
|
|
lfs3_file_t file;
|
|
} sim_file_t;
|
|
sim_file_t **sim_files = malloc(N*sizeof(sim_file_t*));
|
|
lfs3_size_t sim_file_count = 0;
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
nonsense:;
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 5;
|
|
|
|
// open a new file?
|
|
if (op == 0) {
|
|
if (sim_file_count >= N) {
|
|
goto nonsense;
|
|
}
|
|
// choose a pseudo-random number
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
|
|
// already exists?
|
|
bool exist = false;
|
|
uint32_t wprng = 0;
|
|
bool sticky = true;
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
if (sim[j] == x) {
|
|
exist = true;
|
|
wprng = sim_prngs[j];
|
|
sticky = sim_isstickys[j];
|
|
break;
|
|
}
|
|
}
|
|
// choose a random seed if we don't exist
|
|
if (!exist) {
|
|
wprng = TEST_PRNG(&prng);
|
|
sticky = true;
|
|
}
|
|
|
|
lfs3_size_t j = sim_file_count;
|
|
sim_files[j] = malloc(sizeof(sim_file_t));
|
|
|
|
// open the actual file
|
|
char name[256];
|
|
sprintf(name, "batman%03x", x);
|
|
lfs3_file_open(&lfs3, &sim_files[j]->file, name,
|
|
LFS3_O_RDWR
|
|
| LFS3_O_CREAT
|
|
| ((FLUSH) ? LFS3_O_FLUSH : 0)) => 0;
|
|
|
|
// write some initial data if we don't exist
|
|
if (!exist || sticky) {
|
|
uint8_t wbuf[SIZE];
|
|
uint32_t wprng_ = wprng;
|
|
for (lfs3_size_t k = 0; k < SIZE; k++) {
|
|
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &sim_files[j]->file, wbuf, SIZE)
|
|
=> SIZE;
|
|
}
|
|
|
|
// open in our sim
|
|
sim_files[j]->x = x;
|
|
sim_files[j]->sticky = sticky;
|
|
sim_files[j]->zombie = false;
|
|
sim_files[j]->prng = wprng;
|
|
sim_file_count++;
|
|
|
|
// insert into our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= x) {
|
|
// already seen?
|
|
if (k < sim_size && sim[k] == x) {
|
|
// new prng
|
|
sim_prngs[k] = wprng;
|
|
} else {
|
|
// insert
|
|
memmove(&sim[k+1], &sim[k],
|
|
(sim_size-k)*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k+1], &sim_prngs[k],
|
|
(sim_size-k)*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
|
|
(sim_size-k)*sizeof(bool));
|
|
sim_size += 1;
|
|
sim[k] = x;
|
|
sim_prngs[k] = wprng;
|
|
sim_isstickys[k] = sticky;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// write/rewrite a file?
|
|
} else if (op == 1) {
|
|
if (sim_file_count == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file handle
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_file_count;
|
|
lfs3_size_t x = sim_files[j]->x;
|
|
// choose a random seed
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// write to the file
|
|
lfs3_file_rewind(&lfs3, &sim_files[j]->file) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
uint32_t wprng_ = wprng;
|
|
for (lfs3_size_t k = 0; k < SIZE; k++) {
|
|
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &sim_files[j]->file, wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &sim_files[j]->file) => 0;
|
|
|
|
// update sim
|
|
sim_files[j]->prng = wprng;
|
|
if (!sim_files[j]->zombie) {
|
|
// update in our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (sim[k] == x) {
|
|
// new prng
|
|
sim_prngs[k] = wprng;
|
|
// no longer sticky
|
|
sim_isstickys[k] = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update related sim files
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
|
|
// new prng
|
|
sim_files[k]->prng = wprng;
|
|
// no longer sticky
|
|
sim_files[k]->sticky = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// close a file?
|
|
} else if (op == 2) {
|
|
if (sim_file_count == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file handle
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_file_count;
|
|
lfs3_size_t x = sim_files[j]->x;
|
|
bool sticky = sim_files[j]->sticky;
|
|
bool zombie = sim_files[j]->zombie;
|
|
|
|
// this doesn't really test anything, but if we don't close
|
|
// files eventually everything will end up zombies
|
|
|
|
// close the file without affected disk
|
|
lfs3_file_desync(&lfs3, &sim_files[j]->file) => 0;
|
|
lfs3_file_close(&lfs3, &sim_files[j]->file) => 0;
|
|
// clobber closed files to try to catch lingering references
|
|
memset(&sim_files[j]->file, 0xcc, sizeof(lfs3_file_t));
|
|
|
|
// remove from list
|
|
free(sim_files[j]);
|
|
sim_files[j] = sim_files[sim_file_count-1];
|
|
sim_file_count -= 1;
|
|
|
|
// update our sim
|
|
if (sticky && !zombie) {
|
|
// orphaned?
|
|
bool orphan = true;
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
|
|
orphan = false;
|
|
}
|
|
}
|
|
|
|
// if we were never synced, delete from sim
|
|
if (orphan) {
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (sim[k] == x) {
|
|
memmove(&sim[k], &sim[k+1],
|
|
(sim_size-(k+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k], &sim_prngs[k+1],
|
|
(sim_size-(k+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
|
|
(sim_size-(k+1))*sizeof(bool));
|
|
sim_size -= 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove a file?
|
|
} else if (op == 3) {
|
|
if (sim_size == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file to delete
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_size;
|
|
lfs3_size_t x = sim[j];
|
|
|
|
// delete this file
|
|
char name[256];
|
|
sprintf(name, "batman%03x", x);
|
|
lfs3_remove(&lfs3, name) => 0;
|
|
|
|
// delete from our sim
|
|
memmove(&sim[j], &sim[j+1],
|
|
(sim_size-(j+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[j], &sim_prngs[j+1],
|
|
(sim_size-(j+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
sim_size -= 1;
|
|
|
|
// mark any related sim files as zombied
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x) {
|
|
sim_files[k]->zombie = true;
|
|
}
|
|
}
|
|
|
|
// rename a file?
|
|
} else if (op == 4) {
|
|
if (sim_size == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file to rename, and a random number to
|
|
// rename to
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_size;
|
|
lfs3_size_t x = sim[j];
|
|
lfs3_size_t y = TEST_PRNG(&prng) % N;
|
|
uint32_t wprng = sim_prngs[j];
|
|
bool sticky = sim_isstickys[j];
|
|
|
|
// rename this file
|
|
char old_name[256];
|
|
sprintf(old_name, "batman%03x", x);
|
|
char new_name[256];
|
|
sprintf(new_name, "batman%03x", y);
|
|
lfs3_rename(&lfs3, old_name, new_name) => 0;
|
|
|
|
// update our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= y) {
|
|
// renaming and replacing
|
|
if (k < sim_size && sim[k] == y && x != y) {
|
|
// delete the original entry
|
|
memmove(&sim[j], &sim[j+1],
|
|
(sim_size-(j+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[j], &sim_prngs[j+1],
|
|
(sim_size-(j+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
sim_size -= 1;
|
|
if (k > j) {
|
|
k -= 1;
|
|
}
|
|
// update the prng/sticky
|
|
sim_prngs[k] = wprng;
|
|
sim_isstickys[k] = sticky;
|
|
// just renaming
|
|
} else {
|
|
// first delete
|
|
memmove(&sim[j], &sim[j+1],
|
|
(sim_size-(j+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[j], &sim_prngs[j+1],
|
|
(sim_size-(j+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
if (k > j) {
|
|
k -= 1;
|
|
}
|
|
// then insert
|
|
memmove(&sim[k+1], &sim[k],
|
|
(sim_size-1-k)*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k+1], &sim_prngs[k],
|
|
(sim_size-1-k)*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
|
|
(sim_size-1-k)*sizeof(bool));
|
|
sim[k] = y;
|
|
sim_prngs[k] = wprng;
|
|
sim_isstickys[k] = sticky;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update any related sim files
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
// move source files
|
|
if (sim_files[k]->x == x) {
|
|
sim_files[k]->x = y;
|
|
|
|
// mark target files as zombied
|
|
} else if (sim_files[k]->x == y) {
|
|
sim_files[k]->zombie = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check that disk matches our simulation
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
if (sim_isstickys[j]) {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
}
|
|
}
|
|
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
struct lfs3_info info;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
if (sim_isstickys[j]) {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
|
|
uint32_t wprng = sim_prngs[j];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
if (sim_isstickys[j]) {
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => 0;
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// check that our file handles match our simulation
|
|
for (lfs3_size_t j = 0; j < sim_file_count; j++) {
|
|
uint32_t wprng = sim_files[j]->prng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng) % 26);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &sim_files[j]->file) => 0;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &sim_files[j]->file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
free(sim);
|
|
free(sim_prngs);
|
|
free(sim_isstickys);
|
|
for (lfs3_size_t j = 0; j < sim_file_count; j++) {
|
|
lfs3_file_close(&lfs3, &sim_files[j]->file) => 0;
|
|
free(sim_files[j]);
|
|
}
|
|
free(sim_files);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz tests involving many uncreats + zombies + dirs, this gets a bit crazy
|
|
[cases.test_stickynotes_uzd_fuzz]
|
|
# you probably need to flush if you expect errors
|
|
defines.FLUSH = false
|
|
defines.N = [1, 2, 4, 8, 16, 32, 64]
|
|
# do more ops than files to encourage file rewrites
|
|
defines.OPS = '2*N'
|
|
defines.SIZE = [
|
|
'0',
|
|
'FCACHE_SIZE/2',
|
|
'2*FCACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
if = '(SIZE*N)/BLOCK_SIZE <= 16'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// set up a simulation to compare against
|
|
lfs3_size_t *sim = malloc(N*sizeof(lfs3_size_t));
|
|
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
|
|
bool *sim_isstickys = malloc(N*sizeof(bool));
|
|
bool *sim_isdirs = malloc(N*sizeof(bool));
|
|
lfs3_size_t sim_size = 0;
|
|
|
|
typedef struct sim_file {
|
|
lfs3_size_t x;
|
|
bool sticky;
|
|
bool zombie;
|
|
uint32_t prng;
|
|
lfs3_file_t file;
|
|
} sim_file_t;
|
|
sim_file_t **sim_files = malloc(N*sizeof(sim_file_t*));
|
|
lfs3_size_t sim_file_count = 0;
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
nonsense:;
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 8;
|
|
|
|
// open a new file?
|
|
if (op == 0) {
|
|
if (sim_file_count >= N) {
|
|
goto nonsense;
|
|
}
|
|
// choose a pseudo-random number
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
|
|
// already exists?
|
|
bool exist = true;
|
|
uint32_t wprng = 0;
|
|
bool sticky = true;
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
if (sim[j] == x) {
|
|
if (sim_isdirs[j]) {
|
|
goto nonsense;
|
|
}
|
|
exist = true;
|
|
wprng = sim_prngs[j];
|
|
sticky = sim_isstickys[j];
|
|
break;
|
|
}
|
|
}
|
|
// choose a random seed if we don't exist
|
|
if (!exist) {
|
|
wprng = TEST_PRNG(&prng);
|
|
sticky = true;
|
|
}
|
|
|
|
lfs3_size_t j = sim_file_count;
|
|
sim_files[j] = malloc(sizeof(sim_file_t));
|
|
|
|
// open the actual file
|
|
char name[256];
|
|
sprintf(name, "batman%03x", x);
|
|
lfs3_file_open(&lfs3, &sim_files[j]->file, name,
|
|
LFS3_O_RDWR
|
|
| LFS3_O_CREAT
|
|
| ((FLUSH) ? LFS3_O_FLUSH : 0)) => 0;
|
|
|
|
// write some initial data if we don't exist
|
|
if (!exist || sticky) {
|
|
uint8_t wbuf[SIZE];
|
|
uint32_t wprng_ = wprng;
|
|
for (lfs3_size_t k = 0; k < SIZE; k++) {
|
|
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &sim_files[j]->file, wbuf, SIZE)
|
|
=> SIZE;
|
|
}
|
|
|
|
// open in our sim
|
|
sim_files[j]->x = x;
|
|
sim_files[j]->sticky = sticky;
|
|
sim_files[j]->zombie = false;
|
|
sim_files[j]->prng = wprng;
|
|
sim_file_count++;
|
|
|
|
// insert into our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= x) {
|
|
// already seen?
|
|
if (k < sim_size && sim[k] == x) {
|
|
// new prng
|
|
sim_prngs[k] = wprng;
|
|
} else {
|
|
// insert
|
|
memmove(&sim[k+1], &sim[k],
|
|
(sim_size-k)*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k+1], &sim_prngs[k],
|
|
(sim_size-k)*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
|
|
(sim_size-k)*sizeof(bool));
|
|
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
|
|
(sim_size-k)*sizeof(bool));
|
|
sim_size += 1;
|
|
sim[k] = x;
|
|
sim_prngs[k] = wprng;
|
|
sim_isstickys[k] = sticky;
|
|
sim_isdirs[k] = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// write/rewrite a file?
|
|
} else if (op == 1) {
|
|
if (sim_file_count == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file handle
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_file_count;
|
|
lfs3_size_t x = sim_files[j]->x;
|
|
// choose a random seed
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// write to the file
|
|
lfs3_file_rewind(&lfs3, &sim_files[j]->file) => 0;
|
|
uint8_t wbuf[SIZE];
|
|
uint32_t wprng_ = wprng;
|
|
for (lfs3_size_t k = 0; k < SIZE; k++) {
|
|
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_file_write(&lfs3, &sim_files[j]->file, wbuf, SIZE) => SIZE;
|
|
lfs3_file_sync(&lfs3, &sim_files[j]->file) => 0;
|
|
|
|
// update sim
|
|
sim_files[j]->prng = wprng;
|
|
if (!sim_files[j]->zombie) {
|
|
// update in our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= x) {
|
|
// new prng
|
|
sim_prngs[k] = wprng;
|
|
// no longer sticky
|
|
sim_isstickys[k] = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update related sim files
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
|
|
// new prng
|
|
sim_files[k]->prng = wprng;
|
|
// no longer sticky
|
|
sim_files[k]->sticky = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// close a file?
|
|
} else if (op == 2) {
|
|
if (sim_file_count == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file handle
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_file_count;
|
|
lfs3_size_t x = sim_files[j]->x;
|
|
lfs3_size_t sticky = sim_files[j]->sticky;
|
|
lfs3_size_t zombie = sim_files[j]->zombie;
|
|
|
|
// this doesn't really test anything, but if we don't close
|
|
// files eventually everything will end up zombies
|
|
|
|
// close the file without affected disk
|
|
lfs3_file_desync(&lfs3, &sim_files[j]->file) => 0;
|
|
lfs3_file_close(&lfs3, &sim_files[j]->file) => 0;
|
|
// clobber closed files to try to catch lingering references
|
|
memset(&sim_files[j]->file, 0xcc, sizeof(lfs3_file_t));
|
|
|
|
// remove from list
|
|
free(sim_files[j]);
|
|
sim_files[j] = sim_files[sim_file_count-1];
|
|
sim_file_count -= 1;
|
|
|
|
// update our sim
|
|
if (sticky && !zombie) {
|
|
// orphaned?
|
|
bool orphan = true;
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
|
|
orphan = false;
|
|
}
|
|
}
|
|
|
|
// if we were never synced, delete from sim
|
|
if (orphan) {
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (sim[k] == x) {
|
|
memmove(&sim[k], &sim[k+1],
|
|
(sim_size-(k+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k], &sim_prngs[k+1],
|
|
(sim_size-(k+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
|
|
(sim_size-(k+1))*sizeof(bool));
|
|
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
|
|
(sim_size-(k+1))*sizeof(bool));
|
|
sim_size -= 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove a file?
|
|
} else if (op == 3) {
|
|
if (sim_size == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file to delete
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_size;
|
|
lfs3_size_t x = sim[j];
|
|
|
|
// delete this file
|
|
char name[256];
|
|
sprintf(name, "batman%03x", x);
|
|
lfs3_remove(&lfs3, name) => 0;
|
|
|
|
// delete from our sim
|
|
memmove(&sim[j], &sim[j+1],
|
|
(sim_size-(j+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[j], &sim_prngs[j+1],
|
|
(sim_size-(j+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
memmove(&sim_isdirs[j], &sim_isdirs[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
sim_size -= 1;
|
|
|
|
// mark any related sim files as zombied
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x) {
|
|
sim_files[k]->zombie = true;
|
|
}
|
|
}
|
|
|
|
// rename a file?
|
|
} else if (op == 4) {
|
|
if (sim_size == 0) {
|
|
goto nonsense;
|
|
}
|
|
// choose a random file to rename, and a random number to
|
|
// rename to
|
|
lfs3_size_t j = TEST_PRNG(&prng) % sim_size;
|
|
lfs3_size_t x = sim[j];
|
|
lfs3_size_t y = TEST_PRNG(&prng) % N;
|
|
uint32_t wprng = sim_prngs[j];
|
|
bool sticky = sim_isstickys[j];
|
|
bool dir = sim_isdirs[j];
|
|
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= y) {
|
|
// renaming and replacing
|
|
if (k < sim_size && sim[k] == y && x != y) {
|
|
// type mismatch?
|
|
if (sim_isdirs[k] != dir) {
|
|
goto nonsense;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// rename this file
|
|
char old_name[256];
|
|
sprintf(old_name, "batman%03x", x);
|
|
char new_name[256];
|
|
sprintf(new_name, "batman%03x", y);
|
|
lfs3_rename(&lfs3, old_name, new_name) => 0;
|
|
|
|
// update our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= y) {
|
|
// renaming and replacing
|
|
if (k < sim_size && sim[k] == y && x != y) {
|
|
// delete the original entry
|
|
memmove(&sim[j], &sim[j+1],
|
|
(sim_size-(j+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[j], &sim_prngs[j+1],
|
|
(sim_size-(j+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
memmove(&sim_isdirs[j], &sim_isdirs[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
sim_size -= 1;
|
|
if (k > j) {
|
|
k -= 1;
|
|
}
|
|
// update the prng/sticky/dir
|
|
sim_prngs[k] = wprng;
|
|
sim_isstickys[k] = sticky;
|
|
sim_isdirs[k] = dir;
|
|
// just renaming
|
|
} else {
|
|
// first delete
|
|
memmove(&sim[j], &sim[j+1],
|
|
(sim_size-(j+1))*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[j], &sim_prngs[j+1],
|
|
(sim_size-(j+1))*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
memmove(&sim_isdirs[j], &sim_isdirs[j+1],
|
|
(sim_size-(j+1))*sizeof(bool));
|
|
if (k > j) {
|
|
k -= 1;
|
|
}
|
|
// then insert
|
|
memmove(&sim[k+1], &sim[k],
|
|
(sim_size-1-k)*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k+1], &sim_prngs[k],
|
|
(sim_size-1-k)*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
|
|
(sim_size-1-k)*sizeof(bool));
|
|
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
|
|
(sim_size-1-k)*sizeof(bool));
|
|
sim[k] = y;
|
|
sim_prngs[k] = wprng;
|
|
sim_isstickys[k] = sticky;
|
|
sim_isdirs[k] = dir;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update any related sim files
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
// move source files
|
|
if (sim_files[k]->x == x) {
|
|
sim_files[k]->x = y;
|
|
|
|
// mark target files as zombied
|
|
} else if (sim_files[k]->x == y) {
|
|
sim_files[k]->zombie = true;
|
|
}
|
|
}
|
|
|
|
// toss a directory into the mix
|
|
} else if (op == 5) {
|
|
// choose a pseudo-random number
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= x) {
|
|
// already seen?
|
|
if (k < sim_size && sim[k] == x) {
|
|
goto nonsense;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// make the directory
|
|
char name[256];
|
|
sprintf(name, "batman%03x", x);
|
|
lfs3_mkdir(&lfs3, name) => 0;
|
|
|
|
// insert into our sim
|
|
for (lfs3_size_t k = 0;; k++) {
|
|
if (k >= sim_size || sim[k] >= x) {
|
|
// insert
|
|
memmove(&sim[k+1], &sim[k],
|
|
(sim_size-k)*sizeof(lfs3_size_t));
|
|
memmove(&sim_prngs[k+1], &sim_prngs[k],
|
|
(sim_size-k)*sizeof(uint32_t));
|
|
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
|
|
(sim_size-k)*sizeof(bool));
|
|
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
|
|
(sim_size-k)*sizeof(bool));
|
|
sim_size += 1;
|
|
sim[k] = x;
|
|
sim_prngs[k] = 0;
|
|
sim_isdirs[k] = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// mark any related sim files as zombied
|
|
for (lfs3_size_t k = 0; k < sim_file_count; k++) {
|
|
if (sim_files[k]->x == x) {
|
|
sim_files[k]->zombie = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check that disk matches our simulation
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
struct lfs3_info info;
|
|
lfs3_stat(&lfs3, name, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
if (sim_isdirs[j]) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else if (sim_isstickys[j]) {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
}
|
|
}
|
|
|
|
lfs3_dir_t dir;
|
|
lfs3_dir_open(&lfs3, &dir, "/") => 0;
|
|
struct lfs3_info info;
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
lfs3_dir_read(&lfs3, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
if (sim_isdirs[j]) {
|
|
assert(info.type == LFS3_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else if (sim_isstickys[j]) {
|
|
assert(info.type == LFS3_TYPE_STICKYNOTE);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS3_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
}
|
|
}
|
|
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
|
|
lfs3_dir_close(&lfs3, &dir) => 0;
|
|
|
|
for (lfs3_size_t j = 0; j < sim_size; j++) {
|
|
if (sim_isdirs[j]) {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY)
|
|
=> LFS3_ERR_ISDIR;
|
|
|
|
} else {
|
|
char name[256];
|
|
sprintf(name, "batman%03x", sim[j]);
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
|
|
|
uint32_t wprng = sim_prngs[j];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng) % 26);
|
|
}
|
|
|
|
uint8_t rbuf[SIZE];
|
|
if (sim_isstickys[j]) {
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => 0;
|
|
} else {
|
|
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// check that our file handles match our simulation
|
|
for (lfs3_size_t j = 0; j < sim_file_count; j++) {
|
|
uint32_t wprng = sim_files[j]->prng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng) % 26);
|
|
}
|
|
|
|
lfs3_file_rewind(&lfs3, &sim_files[j]->file) => 0;
|
|
uint8_t rbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &sim_files[j]->file, rbuf, SIZE) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
free(sim);
|
|
free(sim_prngs);
|
|
free(sim_isstickys);
|
|
free(sim_isdirs);
|
|
for (lfs3_size_t j = 0; j < sim_file_count; j++) {
|
|
lfs3_file_close(&lfs3, &sim_files[j]->file) => 0;
|
|
free(sim_files[j]);
|
|
}
|
|
free(sim_files);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|