9adb22eee0
The size field in lfs_info doesn't really make sense for stat/dir_read when the file is a directory. Still, we should probably set it to 0 os it's not uninitialized. Fortunately we were already setting size=0 in _most_ cases, this commit is mostly just checking for size=0 in more test cases.
5945 lines
194 KiB
TOML
5945 lines
194 KiB
TOML
# Test orphaned files and their various use cases
|
|
after = ['test_fwrite', 'test_fsync']
|
|
|
|
|
|
# Some specific tests
|
|
[cases.test_forphan_create]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// check that the file doesn't _really_ exist
|
|
lfs_t lfs_;
|
|
lfsr_mount(&lfs_, CFG) => 0;
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs_, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs_, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs_, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs_, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
lfsr_unmount(&lfs_) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// check that the file still doesn't _really_ exist
|
|
lfsr_mount(&lfs_, CFG) => 0;
|
|
// via stat
|
|
lfsr_stat(&lfs_, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs_, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs_, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs_, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
lfsr_unmount(&lfs_) => 0;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the file
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// now it should show up
|
|
lfsr_mount(&lfs_, CFG) => 0;
|
|
// via stat
|
|
lfsr_stat(&lfs_, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs_, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs_, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs_, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs_, &file_) => 0;
|
|
lfsr_unmount(&lfs_) => 0;
|
|
}
|
|
|
|
// close the file
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// now it should show up
|
|
lfsr_mount(&lfs_, CFG) => 0;
|
|
// via stat
|
|
lfsr_stat(&lfs_, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs_, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs_, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs_, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs_, &file_) => 0;
|
|
lfsr_unmount(&lfs_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
|
|
// should still be there
|
|
lfsr_mount(&lfs_, CFG) => 0;
|
|
// via stat
|
|
lfsr_stat(&lfs_, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs_, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs_, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs_, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs_, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs_, &file_) => 0;
|
|
lfsr_unmount(&lfs_) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_create_pl]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs_t lfs;
|
|
int err = lfsr_mount(&lfs, CFG);
|
|
if (err) {
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// create a file
|
|
//
|
|
// note the excl flag
|
|
lfsr_file_t file;
|
|
err = lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL);
|
|
assert(!err || err == LFS_ERR_EXIST);
|
|
|
|
if (err != LFS_ERR_EXIST) {
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// close the file
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// we should be able to read the file now
|
|
lfsr_file_open(&lfs, &file, "gello", LFS_O_RDONLY) => 0;
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// and after remounting
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
lfsr_file_open(&lfs, &file, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_create_many_pl]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
]
|
|
defines.CHUNK = 8
|
|
defines.N = 128
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs_t lfs;
|
|
int err = lfsr_mount(&lfs, CFG);
|
|
if (err) {
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// create N files
|
|
for (lfs_size_t j = 0; j < N; j++) {
|
|
// note the excl flag
|
|
char name[256];
|
|
sprintf(name, "gello%03x", j);
|
|
lfsr_file_t file;
|
|
err = lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL);
|
|
assert(!err || err == LFS_ERR_EXIST);
|
|
|
|
if (err != LFS_ERR_EXIST) {
|
|
// write to the file
|
|
uint32_t prng = 42 + j;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// close the file
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// we should be able to read the files now
|
|
for (lfs_size_t j = 0; j < N; j++) {
|
|
char name[256];
|
|
sprintf(name, "gello%03x", j);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
|
|
uint32_t prng = 42 + j;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// and after remounting
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
for (lfs_size_t j = 0; j < N; j++) {
|
|
char name[256];
|
|
sprintf(name, "gello%03x", j);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
|
|
uint32_t prng = 42 + j;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_create_sync_wr]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// but we should still recieve sync broadcasts on sync/close
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
if (SYNC) {
|
|
// sync the file
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the file
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_create_sync_rw]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
// open a second reference
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// write to the second file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the second file
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the second file
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_create_desync_wdwr]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
// open a second reference
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
// and a third for checking sync broadcasts
|
|
lfsr_file_t file___;
|
|
lfsr_file_open(&lfs, &file___, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync the second file
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the second file
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// now sync the first file, this should overwrite what is written
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &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
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_close(&lfs, &file___) => 0;
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// because the file was desynced, it should still not exist
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// even after a remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// because the file was desynced, it should still not exist
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_wdwr]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
# 0x1 => sync before orphaning
|
|
# 0x2 => sync after orphaning
|
|
defines.SYNC = [0, 1, 2, 3]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a desync file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
// open a second reference
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
// and a third for checking sync broadcasts
|
|
lfsr_file_t file___;
|
|
lfsr_file_open(&lfs, &file___, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
|
|
if (SYNC & 0x1) {
|
|
// sync the second file
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the first file, this should do nothing but discard the
|
|
// file contents
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (SYNC & 0x2) {
|
|
// sync the second file
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close the second file
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
|
|
// now it should show up
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// recieved sync broadcast?
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_close(&lfs, &file___) => 0;
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_unrelated]
|
|
# different number of orphan require different methods of cleanup
|
|
defines.N = 'range(6)'
|
|
defines.M = 'range(6)'
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create N orphans
|
|
lfsr_file_t orphans[N];
|
|
for (lfs_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", o);
|
|
lfsr_file_open(&lfs, &orphans[o], name,
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
uint32_t prng = 42+o;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &orphans[o], wbuf, CHUNK) => CHUNK;
|
|
}
|
|
}
|
|
|
|
// and an unrelated file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
uint32_t prng = 52;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, none of the orphans exist
|
|
// via stat
|
|
struct lfs_info info;
|
|
for (lfs_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", o);
|
|
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
|
|
}
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
for (lfs_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", o);
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, name, LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, name, LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, name, LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// but we should still be able to read our orphans
|
|
for (lfs_size_t o = 0; o < N; o++) {
|
|
lfsr_file_rewind(&lfs, &orphans[o]) => 0;
|
|
prng = 42+o;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &orphans[o], rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 52;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close M orphans
|
|
for (lfs_size_t o = 0; o < M && o < N; o++) {
|
|
lfsr_file_close(&lfs, &orphans[o]) => 0;
|
|
}
|
|
|
|
// create a new unrelated file, this should trigger
|
|
// and orphan cleanup
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "hello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
prng = 62;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
lfsr_file_close(&lfs, &file__);
|
|
|
|
// and now close our original unrelated file
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// and close the remaining orphans
|
|
for (lfs_size_t o = M; o < N; o++) {
|
|
lfsr_file_close(&lfs, &orphans[o]) => 0;
|
|
}
|
|
|
|
// now our file should exist, but none of our orphans
|
|
// via stat
|
|
for (lfs_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", o);
|
|
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
|
|
}
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, "hello", &info) => 0;
|
|
assert(strcmp(info.name, "hello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "hello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
for (lfs_size_t o = 0; o < N; o++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", o);
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, name, LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, name, LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, name, LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
}
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 52;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
lfsr_file_open(&lfs, &file_, "hello", LFS_O_RDONLY) => 0;
|
|
prng = 62;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_open]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfsr_file_t orphans[ORPHANS-1];
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", i);
|
|
lfsr_file_open(&lfs, &orphans[i], name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfsr_file_close(&lfs, &orphans[i]) => 0;
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// create a new file over the orphan
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_mkdir]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfsr_file_t orphans[ORPHANS-1];
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", i);
|
|
lfsr_file_open(&lfs, &orphans[i], name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfsr_file_close(&lfs, &orphans[i]) => 0;
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// create a new dir over the orphan
|
|
lfsr_mkdir(&lfs, "gello") => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// make sure the new dir is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_remove]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfsr_file_t orphans[ORPHANS-1];
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", i);
|
|
lfsr_file_open(&lfs, &orphans[i], name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfsr_file_close(&lfs, &orphans[i]) => 0;
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// orphans aren't real, so remove should fail
|
|
lfsr_remove(&lfs, "gello") => LFS_ERR_NOENT;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_rename_dst]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// make our src file before orphans, otherwise open just cleans
|
|
// things up
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "a/iello" : "iello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/iello" : "iello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfsr_file_t orphans[ORPHANS-1];
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "c/fello%03x" : "fello%03x", i);
|
|
lfsr_file_open(&lfs, &orphans[i], name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfsr_file_close(&lfs, &orphans[i]) => 0;
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// rename onto orphan
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "a/iello" : "iello",
|
|
(INTERDIR) ? "c/gello" : "gello") => 0;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "c" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "c/gello" : "gello",
|
|
LFS_O_RDONLY) => LFS_ERR_ISDIR;
|
|
} else {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "c/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
}
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_orphan_rename_src]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create neighboring orphaned files
|
|
//
|
|
// more orphans requires different techniques for cleaning up orphans
|
|
lfsr_file_t orphans[ORPHANS-1];
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
char name[256];
|
|
sprintf(name, "fello%03x", i);
|
|
lfsr_file_open(&lfs, &orphans[i], name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &orphans[i],
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// create an orphaned file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_DESYNC) => 0;
|
|
lfsr_file_write(&lfs, &file,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
|
|
// close all orphans at once, or else the open calls would just
|
|
// clean up each orphans
|
|
for (lfs_size_t i = 0; i < ORPHANS-1; i++) {
|
|
lfsr_file_close(&lfs, &orphans[i]) => 0;
|
|
}
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// orphans aren't real, so rename should fail
|
|
lfsr_rename(&lfs, "gello", "hello") => LFS_ERR_NOENT;
|
|
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
lfsr_stat(&lfs, "hello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// removed files can not be synced
|
|
lfsr_file_sync(&lfs, &file) => LFS_ERR_NOENT;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// because the file was removed, it should still not exist
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// even after a remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_posthumous]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// removed files can not be synced
|
|
lfsr_file_sync(&lfs, &file) => LFS_ERR_NOENT;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// because the file was removed, it should still not exist
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// even after a remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_rwrw]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a second file
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// removed files can not be synced
|
|
lfsr_file_sync(&lfs, &file) => LFS_ERR_NOENT;
|
|
// but we should be able to sync our second file just fine
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// second file should appear on disk now
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read both file handles
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_rwrw_posthumous]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a second file
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the second file
|
|
uint32_t prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the first file
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// removed files can not be synced
|
|
lfsr_file_sync(&lfs, &file) => LFS_ERR_NOENT;
|
|
// but we should be able to sync our second file just fine
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// second file should appear on disk now
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read both file handles
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_zombie_rwrwrw]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a second file
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a third file
|
|
lfsr_file_t file___;
|
|
lfsr_file_open(&lfs, &file___, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the third file
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file___, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// removed files can not be synced
|
|
lfsr_file_sync(&lfs, &file) => LFS_ERR_NOENT;
|
|
lfsr_file_sync(&lfs, &file__) => LFS_ERR_NOENT;
|
|
// but we should be able to sync our third file just fine
|
|
lfsr_file_sync(&lfs, &file___) => 0;
|
|
|
|
// third file should appear on disk now
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read all file handles
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
lfsr_file_close(&lfs, &file___) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_zombie_rwrwrw_posthumous]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a second file
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// need to sync so we can remove
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a third file
|
|
lfsr_file_t file___;
|
|
lfsr_file_open(&lfs, &file___, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the third file
|
|
uint32_t prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file___, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the first file
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// as far as the filesystem is concerned, the file does not exist yet
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// rdonly rejected
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
|
// non-create rejected
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_WRONLY) => LFS_ERR_NOENT;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDWR) => LFS_ERR_NOENT;
|
|
|
|
// removed files can not be synced
|
|
lfsr_file_sync(&lfs, &file) => LFS_ERR_NOENT;
|
|
lfsr_file_sync(&lfs, &file__) => LFS_ERR_NOENT;
|
|
// but we should be able to sync our third file just fine
|
|
lfsr_file_sync(&lfs, &file___) => 0;
|
|
|
|
// third file should appear on disk now
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// the perhaps surprising thing is we should still be able
|
|
// to read all file handles
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file___) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file___, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
lfsr_file_close(&lfs, &file___) => 0;
|
|
|
|
// check disk again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// check disk again again
|
|
// via stat
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
prng = 42+2;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_open]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// create a new file over the zombie
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, "gello", LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_mkdir]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// create a new dir over the zombie
|
|
lfsr_mkdir(&lfs, "gello") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// make sure the new dir is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_remove]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// zombies aren't real, so remove should fail
|
|
lfsr_remove(&lfs, "gello") => LFS_ERR_NOENT;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_rename_dst]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// make our src file before zombies, just in case
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "c/iello" : "iello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, (INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// rename onto zombie
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => LFS_ERR_ISDIR;
|
|
} else {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
}
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombie_rename_src]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// zombies aren't real, so rename should fail
|
|
lfsr_rename(&lfs, "gello", "hello") => LFS_ERR_NOENT;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
lfsr_stat(&lfs, "hello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombify_mkdir]
|
|
defines.CLOSE = [false, true]
|
|
defines.REMOUNT = [false, true]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a file, not a zombie yet
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &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
|
|
lfsr_mkdir(&lfs, "gello") => 0;
|
|
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// make sure the new dir is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
if (!CLOSE) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_zombify_rename_dst]
|
|
defines.ORPHAN = [false, true]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.CLOSE = [false, true]
|
|
defines.REMOUNT = [false, true]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = [
|
|
'REMOUNT <= CLOSE',
|
|
'!DIR || ORPHAN',
|
|
]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// make our src file before zombies, just in case
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "c/iello" : "iello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a file, not a zombie yet
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
if (!ORPHAN) {
|
|
lfsr_file_sync(&lfs, &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
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => LFS_ERR_ISDIR;
|
|
} else {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
}
|
|
|
|
if (!CLOSE) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_file_on_zombie_remove]
|
|
defines.DIR = [false, true]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
// create a file on top of the zombie
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, "gello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// remove the file
|
|
lfsr_remove(&lfs, "gello") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// just make sure things look ok
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, "gello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_file_on_zombie_rename_dst]
|
|
defines.DIR = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// make our src file before zombies, just in case
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "c/iello" : "iello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, (INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
// create a file on top of the zombie
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "a/gello" : "gello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// rename onto the file
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our zombie
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => LFS_ERR_ISDIR;
|
|
} else {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
}
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# these doesn't really involve scratch files, but we might as well test
|
|
# them here
|
|
[cases.test_forphan_rename]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can rename
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// rename the file
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
// the file should have been renamed
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// close should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_rename_postrename]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// need to sync so we can rename
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// rename the file
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// the file should have been renamed, but zero sized
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => 0;
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// but we should still be able to read our file handle
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// the data should now be visible
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info)
|
|
=> LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// we should still be able to read our file handle
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// the data should now be visible
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_rename_rwrw]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// write to the file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// need to sync so we can rename
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// create a second file
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_TRUNC) => 0;
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// rename the file
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
// the file should have been renamed
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// but we should still be able to read both file handles
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync, note the order
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// the second file's data should now be visible
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info)
|
|
=> LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// both file handles should be updated
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close, note the order
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// close should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_rename_rwrw_postrename]
|
|
defines.SIZE = [
|
|
'CACHE_SIZE/2',
|
|
'2*CACHE_SIZE',
|
|
'BLOCK_SIZE/2',
|
|
'BLOCK_SIZE',
|
|
'2*BLOCK_SIZE',
|
|
'4*BLOCK_SIZE',
|
|
]
|
|
defines.CHUNK = 'lfs_min(64, SIZE)'
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
|
|
// need to sync so we can rename
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// create a second file
|
|
lfsr_file_t file__;
|
|
lfsr_file_open(&lfs, &file__, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_TRUNC) => 0;
|
|
|
|
// rename the file
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
// write to the first file
|
|
uint32_t prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// write to the second file
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfsr_file_write(&lfs, &file__, wbuf, CHUNK) => CHUNK;
|
|
}
|
|
|
|
// the file should have been renamed, but zero sized
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => 0;
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// but we should still be able to read both file handles
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
if (SYNC) {
|
|
// sync, note the order
|
|
lfsr_file_sync(&lfs, &file__) => 0;
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
|
|
// the second file's data should now be visible
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info)
|
|
=> LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// both file handles should be updated
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
|
|
lfsr_file_rewind(&lfs, &file__) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file__, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
}
|
|
|
|
// close, note the order
|
|
lfsr_file_close(&lfs, &file__) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
|
|
// close should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
// remount
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// remount should have no effect
|
|
// via stat
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
prng = 42+1;
|
|
for (lfs_off_t i = 0; i < SIZE; i += CHUNK) {
|
|
uint8_t wbuf[CHUNK];
|
|
for (lfs_size_t j = 0; j < CHUNK; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[CHUNK];
|
|
lfsr_file_read(&lfs, &file_, rbuf, CHUNK) => CHUNK;
|
|
assert(memcmp(wbuf, rbuf, CHUNK) == 0);
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_rename_rename_src]
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
defines.SYNC = [false, true]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTRENAME = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create a file
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
if (!POSTRENAME) {
|
|
lfsr_file_write(&lfs, &file,
|
|
"hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
if (SYNC) {
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
}
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// rename while open
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTRENAME) {
|
|
lfsr_file_write(&lfs, &file,
|
|
"hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
if (SYNC) {
|
|
lfsr_file_sync(&lfs, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// we should still be able to read our file
|
|
lfsr_file_rewind(&lfs, &file) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf))
|
|
=> strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
if ((SYNC || CLOSE >= 1) && !(POSTRENAME && CLOSE >= 2)) {
|
|
assert(info.size == strlen("hello!"));
|
|
} else {
|
|
assert(info.size == 0);
|
|
}
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
if ((SYNC || CLOSE >= 1) && !(POSTRENAME && CLOSE >= 2)) {
|
|
assert(info.size == strlen("hello!"));
|
|
} else {
|
|
assert(info.size == 0);
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
if ((SYNC || CLOSE >= 1) && !(POSTRENAME && CLOSE >= 2)) {
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
} else {
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => 0;
|
|
}
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_forphan_file_on_zombie_rename_src]
|
|
defines.DIR = [false, true]
|
|
defines.EXISTS = [false, true]
|
|
defines.INTERDIR = [false, true]
|
|
defines.DISTANCE = [0, 1, 100]
|
|
# 0 => don't close (before end of test)
|
|
# 1 => close after op
|
|
# 2 => close before op
|
|
defines.CLOSE = [0, 1, 2]
|
|
# 0 => don't remount
|
|
# 1 => remount after op
|
|
# 2 => remount before op
|
|
defines.REMOUNT = [0, 1, 2]
|
|
defines.POSTHUMOUS = [false, true]
|
|
if = 'REMOUNT <= CLOSE'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// create an interesting directory structure
|
|
if (INTERDIR) {
|
|
lfsr_mkdir(&lfs, "a") => 0;
|
|
lfsr_mkdir(&lfs, "b") => 0;
|
|
lfsr_mkdir(&lfs, "c") => 0;
|
|
}
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "b/hello%03x" : "hello%03x", i);
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, name,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
// create our destination first, just in case
|
|
if (EXISTS) {
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "a/gello" : "gello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hmmmmmmmm", strlen("hmmmmmmmm"))
|
|
=> strlen("hmmmmmmmm");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
}
|
|
|
|
// create a zombie
|
|
lfsr_file_t zombie;
|
|
lfsr_file_open(&lfs, &zombie, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
if (!POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
lfsr_file_sync(&lfs, &zombie) => 0;
|
|
lfsr_remove(&lfs, (INTERDIR) ? "c/iello" : "iello") => 0;
|
|
|
|
// create a file on top of the zombie
|
|
if (DIR) {
|
|
lfsr_mkdir(&lfs, (INTERDIR) ? "c/iello" : "iello") => 0;
|
|
} else {
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, (INTERDIR) ? "c/iello" : "iello",
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
lfsr_file_write(&lfs, &file, "hello!", strlen("hello!"))
|
|
=> strlen("hello!");
|
|
lfsr_file_close(&lfs, &file) => 0;
|
|
}
|
|
|
|
if (CLOSE == 2) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 2) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
|
|
// rename while open
|
|
lfsr_rename(&lfs,
|
|
(INTERDIR) ? "c/iello" : "iello",
|
|
(INTERDIR) ? "a/gello" : "gello") => 0;
|
|
|
|
if (CLOSE <= 1 && REMOUNT <= 1) {
|
|
if (POSTHUMOUS) {
|
|
lfsr_file_write(&lfs, &zombie,
|
|
"WoOoOoOoOoO", strlen("WoOoOoOoOoO"))
|
|
=> strlen("WoOoOoOoOoO");
|
|
}
|
|
|
|
// we should still be able to read our file
|
|
lfsr_file_rewind(&lfs, &zombie) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &zombie, rbuf, sizeof(rbuf))
|
|
=> strlen("WoOoOoOoOoO");
|
|
assert(memcmp(rbuf, "WoOoOoOoOoO", strlen("WoOoOoOoOoO")) == 0);
|
|
|
|
if (CLOSE == 1) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
if (REMOUNT == 1) {
|
|
lfsr_unmount(&lfs) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
}
|
|
}
|
|
|
|
// make sure the new file is readable
|
|
// via stat
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, (INTERDIR) ? "a/gello" : "gello", &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
lfsr_stat(&lfs, (INTERDIR) ? "c/iello" : "iello", &info) => LFS_ERR_NOENT;
|
|
// via readdir
|
|
lfsr_dir_t dir;
|
|
lfsr_dir_open(&lfs, &dir, (INTERDIR) ? "a" : "/") => 0;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
if (DIR) {
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
} else {
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == strlen("hello!"));
|
|
}
|
|
if (!INTERDIR) {
|
|
for (lfs_size_t i = 0; i < DISTANCE; i++) {
|
|
char name[256];
|
|
sprintf(name, (INTERDIR) ? "a/hello%03x" : "hello%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == 0);
|
|
}
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
// via open
|
|
if (DIR) {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => LFS_ERR_ISDIR;
|
|
} else {
|
|
lfsr_file_t file_;
|
|
lfsr_file_open(&lfs, &file_, (INTERDIR) ? "a/gello" : "gello",
|
|
LFS_O_RDONLY) => 0;
|
|
uint8_t rbuf[256];
|
|
lfsr_file_read(&lfs, &file_, rbuf, sizeof(rbuf)) => strlen("hello!");
|
|
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
|
lfsr_file_close(&lfs, &file_) => 0;
|
|
}
|
|
|
|
if (CLOSE == 0) {
|
|
lfsr_file_close(&lfs, &zombie) => 0;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|