99156b5573
This is a fun corner case. What happens when you close a desynced scratch file? The obvious answer seems to be just remove the scratch file in lfsr_file_close. But then what if the file is rdonly? desynced because of an error? We really shouldn't write to disk at all when closing a desync or rdonly file. This needs to be a hard rule. So the only option is to defer the work until later somehow. Fortunately, we already have several mechanisms that lead to a very nice solution. I'm very happy with this: 1. There's nothing that says our in-device grm queue needs to always match what's on-disk (we need a separate copy for xoring anyways because of the risk of leb128 encoding differences). So if we have <=2 orphans, we can just push these onto our grm. On the next write operation, the normal grm fixing code takes over and removes the pending orphans O(1). 2. If we have >2 orphans, the best we can do is mark the filesystem as having orphans, and trigger an orphan scan on the next write operation O(nlogn). But how often do you think littlefs's use cases will end up with >2 orphans? Note we also need to scan the opened-file list to make sure we're the _last_ reference to the scratch file. Otherwise we corrupt other opened file handles! --- This commit also includes a fix for a bug where the traversal mdir fell out of sync when dropping mdirs as a part of scratch file cleanup. Found when adding more tests, this would cause scratch files to go unreclaimed.
1748 lines
59 KiB
TOML
1748 lines
59 KiB
TOML
# Test scratch files and their various use cases
|
|
after = ['test_fwrite', 'test_fsync']
|
|
|
|
|
|
# Some specific tests
|
|
[cases.test_fscratch_create]
|
|
defines.SIZE = '4*BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
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);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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;
|
|
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);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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;
|
|
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);
|
|
lfsr_dir_read(&lfs_, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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_fscratch_create_pl]
|
|
defines.SIZE = 'BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
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_fscratch_create_many_pl]
|
|
defines.SIZE = 64
|
|
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_fscratch_create_sync_wr]
|
|
defines.SIZE = '4*BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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;
|
|
|
|
// 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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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;
|
|
|
|
// 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_fscratch_create_sync_rw]
|
|
defines.SIZE = '4*BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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;
|
|
|
|
// 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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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;
|
|
|
|
// 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_fscratch_create_desync_wdwr]
|
|
defines.SIZE = '4*BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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);
|
|
}
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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);
|
|
}
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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_fscratch_orphan]
|
|
defines.SIZE = '4*BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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_fscratch_orphan_wdwr]
|
|
defines.SIZE = '4*BLOCK_SIZE'
|
|
defines.CHUNK = 64
|
|
# 1 => sync before orphaning
|
|
# 2 => 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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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);
|
|
}
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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);
|
|
}
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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;
|
|
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);
|
|
}
|
|
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_fscratch_orphan_open]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after write
|
|
# 2 => remount before write
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_fscratch_orphan_mkdir]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after write
|
|
# 2 => remount before write
|
|
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);
|
|
// 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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "gello") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_fscratch_orphan_remove]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after write
|
|
# 2 => remount before write
|
|
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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_fscratch_orphan_rename_dst]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after write
|
|
# 2 => remount before write
|
|
defines.REMOUNT = [0, 1, 2]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, CFG) => 0;
|
|
lfsr_mount(&lfs, CFG) => 0;
|
|
|
|
// make our src file before orphans, otherwise open just cleans
|
|
// things up
|
|
lfsr_file_t file;
|
|
lfsr_file_open(&lfs, &file, "hello",
|
|
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, "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_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;
|
|
}
|
|
|
|
// rename onto orphan
|
|
lfsr_rename(&lfs, "hello", "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, "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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
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_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_fscratch_orphan_rename_src]
|
|
defines.ORPHANS = [1, 2, 3, 100]
|
|
# 0 => don't remount
|
|
# 1 => remount after write
|
|
# 2 => remount before write
|
|
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;
|
|
// 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);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|