diff --git a/lfs.c b/lfs.c index 69b3bc32..9b01076c 100644 --- a/lfs.c +++ b/lfs.c @@ -6950,6 +6950,8 @@ enum { LFSR_DID_ROOT = 0, }; +// TODO this function may need another look over +// // lookup full paths in our mtree // // if not found, mdir_/did_/name_ will at least be set up @@ -6960,16 +6962,13 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path, lfsr_mdir_t *mdir_, lfsr_tag_t *tag_, lfsr_did_t *did_, const char **name_, lfs_size_t *name_size_) { // setup root - lfsr_mdir_t mdir; - mdir.mid = 0; + lfsr_mdir_t mdir = {.mid = 0}; lfsr_tag_t tag = LFSR_TAG_DIR; lfsr_did_t did = LFSR_DID_ROOT; + // use mid=-1 to indicate we can't even create the path if (mdir_) { - *mdir_ = mdir; - } - if (tag_) { - *tag_ = tag; + mdir_->mid = -1; } // we reduce path to a single name if we can find it @@ -7013,10 +7012,11 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path, // found end of path, we must be done parsing our path now if (name[0] == '\0') { - // generally we don't allow operations that change our root, - // report root as inval, but let upper layers intercept this - if (lfsr_mid_isroot(mdir.mid)) { - return LFS_ERR_INVAL; + if (mdir_) { + *mdir_ = mdir; + } + if (tag_) { + *tag_ = tag; } return 0; } @@ -7048,8 +7048,7 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path, return err; } - // keep track of what we've seen, but only if we're the last name - // in our path + // keep track of where to insert if we are the last name in our path if (strchr(name, '/') == NULL) { if (mdir_) { *mdir_ = mdir; @@ -7068,8 +7067,7 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path, } } - // error if not found, note we update things first so mdir - // gets updated with where to insert correctly + // error if not found if (err == LFS_ERR_NOENT) { return LFS_ERR_NOENT; } @@ -8543,11 +8541,11 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) { err = lfsr_mtree_pathlookup(lfs, path, &mdir, NULL, &did, &name, &name_size); - if (err && (err != LFS_ERR_NOENT || lfsr_mdir_isroot(&mdir))) { + if (err && (err != LFS_ERR_NOENT || mdir.mid == -1)) { return err; } - // woah, already exists? + // already exists? if (err != LFS_ERR_NOENT) { return LFS_ERR_EXIST; } @@ -8672,6 +8670,11 @@ int lfsr_remove(lfs_t *lfs, const char *path) { return err; } + // as funny as it would be, you can't remove the root + if (lfsr_mdir_isroot(&mdir)) { + return LFS_ERR_INVAL; + } + // if we're removing a directory, we need to also remove the // bookmark entry lfsr_grm_t grm = lfs->grm; @@ -8759,6 +8762,11 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { return err; } + // as funny as it would be, you can't rename the root + if (lfsr_mdir_isroot(&old_mdir)) { + return LFS_ERR_INVAL; + } + // mark old entry for removal with a grm lfsr_grm_t grm = lfs->grm; lfsr_grm_pushrm(&grm, old_mdir.mid); @@ -8772,7 +8780,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { err = lfsr_mtree_pathlookup(lfs, new_path, &new_mdir, &new_tag, &new_did, &new_name, &new_name_size); - if (err && (err != LFS_ERR_NOENT || lfsr_mdir_isroot(&new_mdir))) { + if (err && (err != LFS_ERR_NOENT || new_mdir.mid == -1)) { return err; } bool exists = (err != LFS_ERR_NOENT); @@ -8793,7 +8801,9 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { } else { // renaming different types is an error if (old_tag != new_tag) { - return LFS_ERR_ISDIR; + return (new_tag == LFSR_TAG_DIR) + ? LFS_ERR_ISDIR + : LFS_ERR_NOTDIR; } // TODO is it? is this check necessary? @@ -8953,12 +8963,12 @@ int lfsr_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { int err = lfsr_mtree_pathlookup(lfs, path, &mdir, &tag, NULL, &name, &name_size); - if (err && err != LFS_ERR_INVAL) { + if (err) { return err; } // special case for root - if (err == LFS_ERR_INVAL) { + if (lfsr_mdir_isroot(&mdir)) { strcpy(info->name, "/"); info->type = LFS_TYPE_DIR; return 0; @@ -8975,7 +8985,7 @@ int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path) { int err = lfsr_mtree_pathlookup(lfs, path, &mdir, &tag, NULL, NULL, NULL); - if (err && err != LFS_ERR_INVAL) { + if (err) { return err; } @@ -8985,7 +8995,7 @@ int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path) { } // read our did from the mdir, unless we're root - if (err == LFS_ERR_INVAL) { + if (lfsr_mdir_isroot(&mdir)) { dir->did = 0; } else { lfsr_data_t data; @@ -9266,7 +9276,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file, int err = lfsr_mtree_pathlookup(lfs, path, &file->mdir, &tag, &did, &name, &name_size); - if (err && err != LFS_ERR_NOENT) { + if (err && (err != LFS_ERR_NOENT || file->mdir.mid == -1)) { return err; } diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml index f1e8153b..788b0b8b 100644 --- a/tests/test_dirs.toml +++ b/tests/test_dirs.toml @@ -281,16 +281,14 @@ code = ''' } // try to make root, which doesn't make sense - err = lfsr_mkdir(&lfs, "/"); - assert(err == LFS_ERR_EXIST || err == LFS_ERR_INVAL); + lfsr_mkdir(&lfs, "/") => LFS_ERR_EXIST; // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PLS && err == LFS_ERR_EXIST)); // try to make root, which doesn't make sense - err = lfsr_mkdir(&lfs, "/"); - assert(err == LFS_ERR_EXIST || err == LFS_ERR_INVAL); + lfsr_mkdir(&lfs, "/") => LFS_ERR_EXIST; // remount? if (REMOUNT) { diff --git a/tests/test_files.toml b/tests/test_files.toml index ce7eed7b..741ae458 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -288,7 +288,7 @@ code = ''' // try to rename a directory onto our file lfsr_mkdir(&lfs, "not_hello") => 0; - lfsr_rename(&lfs, "not_hello", "hello") => LFS_ERR_ISDIR; + lfsr_rename(&lfs, "not_hello", "hello") => LFS_ERR_NOTDIR; // remount? if (REMOUNT) { @@ -426,16 +426,16 @@ code = ''' // try reading our root as a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_INVAL; + lfsr_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_ISDIR; // try writing our root as a file - lfsr_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_INVAL; + lfsr_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, "/", - LFS_O_WRONLY | LFS_O_TRUNC) => LFS_ERR_INVAL; + LFS_O_WRONLY | LFS_O_TRUNC) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, "/", - LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, "/", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => LFS_ERR_INVAL; + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => LFS_ERR_ISDIR; // try rename a file on top of our directory lfsr_file_open(&lfs, &file, "not_hello", @@ -446,7 +446,82 @@ code = ''' lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize; lfsr_file_close(&lfs, &file) => 0; - lfsr_rename(&lfs, "not_hello", "/") => LFS_ERR_INVAL; + lfsr_rename(&lfs, "not_hello", "/") => LFS_ERR_ISDIR; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // check our root with stat + struct lfs_info info; + lfsr_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir read + 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, "not_hello") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == wsize); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // did we corrupt our renaming file? + // try reading our file + lfsr_file_open(&lfs, &file, "not_hello", LFS_O_RDONLY) => 0; + // is size correct? + lfsr_file_size(&lfs, &file) => wsize; + // try reading + uint8_t rbuf[8192]; + memset(rbuf, 0xaa, sizeof(rbuf)); + lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => wsize; + assert(memcmp(rbuf, wbuf, wsize) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# an invalid path is also not a file (kind of?) +[cases.test_files_noent_not_file] +defines.REMOUNT = [false, true] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + // try reading our invalid path as a file + lfsr_file_t file; + lfsr_file_open(&lfs, &file, "no/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; + + // try writing our root as a file + lfsr_file_open(&lfs, &file, "no/hello", LFS_O_WRONLY) => LFS_ERR_NOENT; + lfsr_file_open(&lfs, &file, "no/hello", + LFS_O_WRONLY | LFS_O_TRUNC) => LFS_ERR_NOENT; + lfsr_file_open(&lfs, &file, "no/hello", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfsr_file_open(&lfs, &file, "no/hello", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => LFS_ERR_NOENT; + + // try rename a file on top of our invalid path + lfsr_file_open(&lfs, &file, "not_hello", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + uint8_t wbuf[8192]; + strcpy((char*)wbuf, "Hello World!"); + lfs_size_t wsize = strlen((const char*)wbuf); + lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize; + lfsr_file_close(&lfs, &file) => 0; + + lfsr_rename(&lfs, "not_hello", "no/hello") => LFS_ERR_NOENT; // remount? if (REMOUNT) { @@ -838,6 +913,429 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +# test renaming a file to itself +[cases.test_files_mv_noop] +defines.SIZE = [ + '0', + 'CACHE_SIZE/2', + '2*CACHE_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '4*BLOCK_SIZE', +] +defines.REMOUNT = [false, true] +defines.CACHE_SIZE = 64 +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, "amethyst", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t wbuf[SIZE]; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < SIZE; i++) { + wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // rename the file + lfsr_rename(&lfs, "amethyst", "amethyst") => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // check our file with stat + struct lfs_info info; + lfsr_stat(&lfs, "amethyst", &info) => 0; + assert(strcmp(info.name, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + + // and with dir read + 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, "amethyst") == 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; + + // try reading our file + lfsr_file_open(&lfs, &file, "amethyst", LFS_O_RDONLY) => 0; + // is size correct? + lfsr_file_size(&lfs, &file) => SIZE; + // try reading + uint8_t rbuf[2*SIZE]; + memset(rbuf, 0xaa, 2*SIZE); + lfsr_file_read(&lfs, &file, rbuf, 2*SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test renaming a file onto a dir +[cases.test_files_mv_not_file] +defines.SIZE = [ + '0', + 'CACHE_SIZE/2', + '2*CACHE_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '4*BLOCK_SIZE', +] +defines.REMOUNT = [false, true] +defines.CACHE_SIZE = 64 +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, "amethyst", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t wbuf[SIZE]; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < SIZE; i++) { + wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // create a dir + lfsr_mkdir(&lfs, "basalt") => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // rename the file + lfsr_rename(&lfs, "amethyst", "basalt") => LFS_ERR_ISDIR; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // check that nothing changed in our file/dir with stat + struct lfs_info info; + lfsr_stat(&lfs, "amethyst", &info) => 0; + assert(strcmp(info.name, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + lfsr_stat(&lfs, "basalt", &info) => 0; + assert(strcmp(info.name, "basalt") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir read + 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, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "basalt") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // try reading our file + lfsr_file_open(&lfs, &file, "amethyst", LFS_O_RDONLY) => 0; + // is size correct? + lfsr_file_size(&lfs, &file) => SIZE; + // try reading + uint8_t rbuf[2*SIZE]; + memset(rbuf, 0xaa, 2*SIZE); + lfsr_file_read(&lfs, &file, rbuf, 2*SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test renaming a dir onto a file +[cases.test_files_mv_not_dir] +defines.SIZE = [ + '0', + 'CACHE_SIZE/2', + '2*CACHE_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '4*BLOCK_SIZE', +] +defines.REMOUNT = [false, true] +defines.CACHE_SIZE = 64 +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, "amethyst", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t wbuf[SIZE]; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < SIZE; i++) { + wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // create a dir + lfsr_mkdir(&lfs, "basalt") => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // rename the dir + lfsr_rename(&lfs, "basalt", "amethyst") => LFS_ERR_NOTDIR; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // check that nothing changed in our file/dir with stat + struct lfs_info info; + lfsr_stat(&lfs, "amethyst", &info) => 0; + assert(strcmp(info.name, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + lfsr_stat(&lfs, "basalt", &info) => 0; + assert(strcmp(info.name, "basalt") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir read + 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, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "basalt") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // try reading our file + lfsr_file_open(&lfs, &file, "amethyst", LFS_O_RDONLY) => 0; + // is size correct? + lfsr_file_size(&lfs, &file) => SIZE; + // try reading + uint8_t rbuf[2*SIZE]; + memset(rbuf, 0xaa, 2*SIZE); + lfsr_file_read(&lfs, &file, rbuf, 2*SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test renaming a file onto root +[cases.test_files_mv_not_root] +defines.SIZE = [ + '0', + 'CACHE_SIZE/2', + '2*CACHE_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '4*BLOCK_SIZE', +] +defines.REMOUNT = [false, true] +defines.CACHE_SIZE = 64 +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, "amethyst", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t wbuf[SIZE]; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < SIZE; i++) { + wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // rename the file + lfsr_rename(&lfs, "amethyst", "/") => LFS_ERR_ISDIR; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // check that nothing changed in our file/dir with stat + struct lfs_info info; + lfsr_stat(&lfs, "amethyst", &info) => 0; + assert(strcmp(info.name, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + + // and with dir read + 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, "amethyst") == 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; + + // try reading our file + lfsr_file_open(&lfs, &file, "amethyst", LFS_O_RDONLY) => 0; + // is size correct? + lfsr_file_size(&lfs, &file) => SIZE; + // try reading + uint8_t rbuf[2*SIZE]; + memset(rbuf, 0xaa, 2*SIZE); + lfsr_file_read(&lfs, &file, rbuf, 2*SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test renaming a file onto an invalid path +[cases.test_files_mv_not_noent] +defines.SIZE = [ + '0', + 'CACHE_SIZE/2', + '2*CACHE_SIZE', + 'BLOCK_SIZE/2', + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '4*BLOCK_SIZE', +] +defines.REMOUNT = [false, true] +defines.CACHE_SIZE = 64 +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, "amethyst", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t wbuf[SIZE]; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < SIZE; i++) { + wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); + } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // rename the file + lfsr_rename(&lfs, "amethyst", "no/amethyst") => LFS_ERR_NOENT; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + // check that nothing changed in our file/dir with stat + struct lfs_info info; + lfsr_stat(&lfs, "amethyst", &info) => 0; + assert(strcmp(info.name, "amethyst") == 0); + assert(info.type == LFS_TYPE_REG); + assert(info.size == SIZE); + + // and with dir read + 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, "amethyst") == 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; + + // try reading our file + lfsr_file_open(&lfs, &file, "amethyst", LFS_O_RDONLY) => 0; + // is size correct? + lfsr_file_size(&lfs, &file) => SIZE; + // try reading + uint8_t rbuf[2*SIZE]; + memset(rbuf, 0xaa, 2*SIZE); + lfsr_file_read(&lfs, &file, rbuf, 2*SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfsr_file_close(&lfs, &file) => 0; + + lfsr_unmount(&lfs) => 0; +''' + # TODO # [cases.test_files_rm]