From c56124f90f414f31f10c9bd02760f8e0a3c419f2 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 4 Sep 2023 16:17:35 -0500 Subject: [PATCH] Added handling of readonly grms to the mtree layer This bit of code allows us to mount an "inconsistent" filesystem after powerloss and behave as though we've fixed any pending grms without actually fixing the grms. This lets the filesystem appear consistent without needing to modify the disk, and allows truely readonly mounts without sacrificing powerloss-resilience. This works by just checking any readonly mid operations against pending grms and returning NOENT if a fix would remove the mid. Fortunately the more complex mid operations occur when mutating the filesystem, which we can ignore as any mutation must be preceded by fixing pending grms. This check has been added to lfsr_mtree_namelookup and lfsr_mtree_seek, which should propagate the behavior to high-level functions with minimal code impact. This leaves only lfsr_mtree_lookup ignoring pending grms, which is useful because we need it to actually fix the grms. I don't believe this function will ever be called by a high-level function directly... Coverage of readonly grms have also been added to the tests. --- lfs.c | 63 ++- tests/test_dtree.toml | 1010 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 1030 insertions(+), 43 deletions(-) diff --git a/lfs.c b/lfs.c index 30d815c6..271c8e3f 100644 --- a/lfs.c +++ b/lfs.c @@ -4882,30 +4882,39 @@ static int lfsr_mtree_parent(lfs_t *lfs, const lfs_block_t blocks[static 2], } static int lfsr_mtree_seek(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_off_t off) { - // calculate new mid, be careful to avoid rid overflow - lfs_size_t bid = mdir->mid & lfsr_mbidmask(lfs); - lfs_size_t rid = (mdir->mid & lfsr_mridmask(lfs)) + off; - // lookup mdirs until we find our rid, we need to do this because - // we don't know how many rids are in each mdir until we fetch - while (rid >= mdir->u.m.weight) { - // end of mtree? - if (bid+lfsr_mweight(lfs) >= lfsr_mtree_weight(lfs)) { - // if we hit the end of the mtree, park the mdir so all future - // seeks return noent - mdir->mid = bid + mdir->u.m.weight; - return LFS_ERR_NOENT; + while (true) { + // calculate new mid, be careful to avoid rid overflow + lfs_size_t bid = mdir->mid & lfsr_mbidmask(lfs); + lfs_size_t rid = (mdir->mid & lfsr_mridmask(lfs)) + off; + // lookup mdirs until we find our rid, we need to do this because + // we don't know how many rids are in each mdir until we fetch + while (rid >= mdir->u.m.weight) { + // end of mtree? + if (bid+lfsr_mweight(lfs) >= lfsr_mtree_weight(lfs)) { + // if we hit the end of the mtree, park the mdir so all future + // seeks return noent + mdir->mid = bid + mdir->u.m.weight; + return LFS_ERR_NOENT; + } + + bid += lfsr_mweight(lfs); + rid -= mdir->u.m.weight; + int err = lfsr_mtree_lookup(lfs, bid, mdir); + if (err) { + return err; + } } - bid += lfsr_mweight(lfs); - rid -= mdir->u.m.weight; - int err = lfsr_mtree_lookup(lfs, bid, mdir); - if (err) { - return err; + mdir->mid = bid + rid; + + // wait are we grmed? pretend this mid doesn't exist + if (mdir->mid == lfs->grm.rms[0] + || mdir->mid == lfs->grm.rms[1]) { + continue; } + + return 0; } - - mdir->mid = bid + rid; - return 0; } @@ -5852,14 +5861,22 @@ static int lfsr_mtree_namelookup(lfs_t *lfs, int err = lfsr_mdir_namelookup(lfs, &mdir, did, name, name_size, &rid, tag_, data_); - - // update mdir weith best place to insert even if we fail + // update mdir with best place to insert even if we fail mdir.mid += rid; if (mdir_) { *mdir_ = mdir; } + if (err) { + return err; + } - return err; + // wait are we grmed? pretend this mid doesn't exist + if (mdir.mid == lfs->grm.rms[0] + || mdir.mid == lfs->grm.rms[1]) { + return LFS_ERR_NOENT; + } + + return 0; } diff --git a/tests/test_dtree.toml b/tests/test_dtree.toml index f05351fb..07699ed0 100644 --- a/tests/test_dtree.toml +++ b/tests/test_dtree.toml @@ -196,6 +196,77 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +# test that dir existance is the same before/after mkconsistent +[cases.test_dtree_mkdir_consistent] +defines.REMOUNT = [false, true] +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; + } + + // check if dir exists before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool exists = !err; + + // 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); + if (exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // make a directory + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == exists); + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.pgrm[0] == 0); + } + + // check that our mkdir worked with stat + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir_read + 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, "ardvark") == 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; +''' + # test what happens if we try to make root [cases.test_dtree_mkdir_root] defines.REMOUNT = [false, true] @@ -318,13 +389,54 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; } + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); // remount? if (REMOUNT) { @@ -335,7 +447,6 @@ code = ''' } // check that our mkdir worked - struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); @@ -346,7 +457,6 @@ code = ''' assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -381,13 +491,82 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; } + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "ardvark/banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "ardvark/banana/cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + err = lfsr_dir_open(&lfs, &dir, "/ardvark"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == a_exists); + if (a_exists) { + 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); + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + + err = lfsr_dir_open(&lfs, &dir, "/ardvark/banana"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == b_exists); + if (b_exists) { + 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); + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "ardvark/banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); // remount? if (REMOUNT) { @@ -398,7 +577,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); @@ -409,7 +587,6 @@ code = ''' assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -1008,19 +1185,87 @@ code = ''' assert(lfs_crc32c(0, "e_LptKHkHH", 10) == 0x12345678); assert(lfs_crc32c(0, "f_lUoVuhJH", 10) == 0x12345678); + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "a_SNmwMTHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "b_skvjpWJH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "c_OnOQhVPH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + err = lfsr_stat(&lfs, "d_puMpPjRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool d_exists = !err; + err = lfsr_stat(&lfs, "e_LptKHkHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool e_exists = !err; + err = lfsr_stat(&lfs, "f_lUoVuhJH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool f_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "a_SNmwMTHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "b_skvjpWJH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "c_OnOQhVPH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (d_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "d_puMpPjRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (e_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "e_LptKHkHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (f_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "f_lUoVuhJH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make directories err = lfsr_mkdir(&lfs, "a_SNmwMTHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "b_skvjpWJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "c_OnOQhVPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); err = lfsr_mkdir(&lfs, "d_puMpPjRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == d_exists); err = lfsr_mkdir(&lfs, "e_LptKHkHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == e_exists); err = lfsr_mkdir(&lfs, "f_lUoVuhJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == f_exists); // remount? if (REMOUNT) { @@ -1031,7 +1276,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "a_SNmwMTHH", &info) => 0; assert(strcmp(info.name, "a_SNmwMTHH") == 0); assert(info.type == LFS_TYPE_DIR); @@ -1051,7 +1295,6 @@ code = ''' assert(strcmp(info.name, "f_lUoVuhJH") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -1103,19 +1346,87 @@ code = ''' assert(lfs_crc32c(0, "e_VNunKMPH", 10) == 0x00000000); assert(lfs_crc32c(0, "f_vknsvNRH", 10) == 0x00000000); + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "a_IplRNrPH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "b_iUwOsqRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "c_UPNtkpHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + err = lfsr_stat(&lfs, "d_jKLUSLJH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool d_exists = !err; + err = lfsr_stat(&lfs, "e_VNunKMPH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool e_exists = !err; + err = lfsr_stat(&lfs, "f_vknsvNRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool f_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "a_IplRNrPH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "b_iUwOsqRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "c_UPNtkpHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (d_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "d_jKLUSLJH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (e_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "e_VNunKMPH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (f_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "f_vknsvNRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make directories err = lfsr_mkdir(&lfs, "a_IplRNrPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "b_iUwOsqRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "c_UPNtkpHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); err = lfsr_mkdir(&lfs, "d_jKLUSLJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == d_exists); err = lfsr_mkdir(&lfs, "e_VNunKMPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == e_exists); err = lfsr_mkdir(&lfs, "f_vknsvNRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == f_exists); // remount? if (REMOUNT) { @@ -1126,7 +1437,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "a_IplRNrPH", &info) => 0; assert(strcmp(info.name, "a_IplRNrPH") == 0); assert(info.type == LFS_TYPE_DIR); @@ -1146,7 +1456,6 @@ code = ''' assert(strcmp(info.name, "f_vknsvNRH") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -1200,19 +1509,87 @@ code = ''' assert(lfs_crc32c(0, "e_vQtPStPH", 10) == 0xffffffff); assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "a_iomlVKPH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "b_IJvqkHRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "c_uOOJsIHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + err = lfsr_stat(&lfs, "d_JTMkKuJH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool d_exists = !err; + err = lfsr_stat(&lfs, "e_vQtPStPH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool e_exists = !err; + err = lfsr_stat(&lfs, "f_VtoMnwRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool f_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "a_iomlVKPH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "b_IJvqkHRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "c_uOOJsIHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (d_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "d_JTMkKuJH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (e_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "e_vQtPStPH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (f_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "f_VtoMnwRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make directories err = lfsr_mkdir(&lfs, "a_iomlVKPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "b_IJvqkHRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "c_uOOJsIHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); err = lfsr_mkdir(&lfs, "d_JTMkKuJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == d_exists); err = lfsr_mkdir(&lfs, "e_vQtPStPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == e_exists); err = lfsr_mkdir(&lfs, "f_VtoMnwRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == f_exists); // remount? if (REMOUNT) { @@ -1223,7 +1600,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "a_iomlVKPH", &info) => 0; assert(strcmp(info.name, "a_iomlVKPH") == 0); assert(info.type == LFS_TYPE_DIR); @@ -1243,7 +1619,6 @@ code = ''' assert(strcmp(info.name, "f_VtoMnwRH") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -1297,19 +1672,87 @@ code = ''' assert(lfs_crc32c(0, "e_thrRIsRH", 10) == 0x00004000); assert(lfs_crc32c(0, "f_pNtQTPJH", 10) == 0x00004001); + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "a_IOtUptRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "b_nquQsKHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "c_vwQtKjHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + err = lfsr_stat(&lfs, "d_sVrvrWHH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool d_exists = !err; + err = lfsr_stat(&lfs, "e_thrRIsRH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool e_exists = !err; + err = lfsr_stat(&lfs, "f_pNtQTPJH", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool f_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "a_IOtUptRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "b_nquQsKHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "c_vwQtKjHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (d_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "d_sVrvrWHH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (e_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "e_thrRIsRH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (f_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "f_pNtQTPJH") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make directories err = lfsr_mkdir(&lfs, "a_IOtUptRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "b_nquQsKHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "c_vwQtKjHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); err = lfsr_mkdir(&lfs, "d_sVrvrWHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == d_exists); err = lfsr_mkdir(&lfs, "e_thrRIsRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == e_exists); err = lfsr_mkdir(&lfs, "f_pNtQTPJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == f_exists); // remount? if (REMOUNT) { @@ -1320,7 +1763,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "a_IOtUptRH", &info) => 0; assert(strcmp(info.name, "a_IOtUptRH") == 0); assert(info.type == LFS_TYPE_DIR); @@ -1340,7 +1782,6 @@ code = ''' assert(strcmp(info.name, "f_pNtQTPJH") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -1576,6 +2017,102 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +# test that dir existance is the same before/after mkconsistent +[cases.test_dtree_rm_consistent] +defines.REMOUNT = [false, true] +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; + } + + // check if dir exists before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool exists = !err; + + // 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); + if (exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // make a directory + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == exists); + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.pgrm[0] == 0); + } + + // check that our mkdir worked with stat + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir_read + 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, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // and remove the directory + lfsr_remove(&lfs, "ardvark") => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.pgrm[0] == 0); + } + + // check that remove worked with stat + lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT; + + // and with dir_read + 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; +''' + # test what happens if we try to remove root [cases.test_dtree_rm_root] defines.REMOUNT = [false, true] @@ -1645,13 +2182,54 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; } + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); // remount? if (REMOUNT) { @@ -1662,7 +2240,6 @@ code = ''' } // check that our mkdir worked - struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); @@ -1673,7 +2250,6 @@ code = ''' assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -1801,13 +2377,82 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; } + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "ardvark/banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "ardvark/banana/cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + err = lfsr_dir_open(&lfs, &dir, "/ardvark"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == a_exists); + if (a_exists) { + 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); + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + + err = lfsr_dir_open(&lfs, &dir, "/ardvark/banana"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == b_exists); + if (b_exists) { + 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); + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "ardvark/banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); // remount? if (REMOUNT) { @@ -1818,7 +2463,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); @@ -1829,7 +2473,6 @@ code = ''' assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -3357,6 +4000,123 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' +# test that dir existance is the same before/after mkconsistent +[cases.test_dtree_mv_consistent] +defines.REMOUNT = [false, true] +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; + } + + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + + // 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // make a directory + err = lfsr_mkdir(&lfs, "ardvark"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); + + // clean up interrupted renames + if (TEST_PL) { + err = lfsr_remove(&lfs, "banana"); + assert(!err || err == LFS_ERR_NOENT); + assert(!err == b_exists); + } + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.pgrm[0] == 0); + } + + // check that our mkdir worked with stat + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir_read + 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, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // now rename the directory + lfsr_rename(&lfs, "ardvark", "banana") => 0; + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.pgrm[0] == 0); + } + + // check that rename worked with stat + lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT; + lfsr_stat(&lfs, "banana", &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir_read + 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, "banana") == 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; +''' + # test what happens if we try to rename root [cases.test_dtree_mv_root] defines.REMOUNT = [false, true] @@ -3423,22 +4183,90 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; } + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + err = lfsr_stat(&lfs, "disco", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool d_exists = !err; + err = lfsr_stat(&lfs, "eggplant", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool e_exists = !err; + err = lfsr_stat(&lfs, "fish", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool f_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (d_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "disco") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (e_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "eggplant") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (f_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "fish") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); // clean up interrupted renames if (TEST_PL) { err = lfsr_remove(&lfs, "disco"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == d_exists); err = lfsr_remove(&lfs, "eggplant"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == e_exists); err = lfsr_remove(&lfs, "fish"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == f_exists); } // remount? @@ -3450,7 +4278,6 @@ code = ''' } // check that our mkdir worked - struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); @@ -3461,7 +4288,6 @@ code = ''' assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); @@ -3619,28 +4445,174 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; } + // check if dirs exist before mkconsistent + struct lfs_info info; + err = lfsr_stat(&lfs, "ardvark", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool a_exists = !err; + err = lfsr_stat(&lfs, "ardvark/banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool b_exists = !err; + err = lfsr_stat(&lfs, "ardvark/banana/cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool c_exists = !err; + err = lfsr_stat(&lfs, "disco", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool d_exists = !err; + err = lfsr_stat(&lfs, "disco/eggplant", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool e_exists = !err; + err = lfsr_stat(&lfs, "disco/eggplant/fish", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool f_exists = !err; + err = lfsr_stat(&lfs, "disco/banana", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool db_exists = !err; + err = lfsr_stat(&lfs, "disco/banana/cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool dbc_exists = !err; + err = lfsr_stat(&lfs, "disco/eggplant/cat", &info); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + bool dec_exists = !err; + + 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); + if (a_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (d_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "disco") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + err = lfsr_dir_open(&lfs, &dir, "/ardvark"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == a_exists); + if (a_exists) { + 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); + if (b_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + + err = lfsr_dir_open(&lfs, &dir, "/ardvark/banana"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == b_exists); + if (b_exists) { + 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); + if (c_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + + err = lfsr_dir_open(&lfs, &dir, "/disco"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == d_exists); + if (d_exists) { + 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); + if (db_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "banana") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (e_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "eggplant") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + + err = lfsr_dir_open(&lfs, &dir, "/disco/eggplant"); + assert(err == LFS_ERR_NOENT || (TEST_PL && !err)); + assert(!err == e_exists); + if (e_exists) { + 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); + if (dec_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "cat") == 0); + assert(info.type == LFS_TYPE_DIR); + } + if (f_exists) { + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "fish") == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == a_exists); err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == b_exists); err = lfsr_mkdir(&lfs, "ardvark/banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + assert((err == LFS_ERR_EXIST) == c_exists); // clean up interrupted renames if (TEST_PL) { err = lfsr_remove(&lfs, "disco/eggplant/fish"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == f_exists); err = lfsr_remove(&lfs, "disco/eggplant/cat"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == dec_exists); err = lfsr_remove(&lfs, "disco/eggplant"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == e_exists); err = lfsr_remove(&lfs, "disco/banana/cat"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == dbc_exists); err = lfsr_remove(&lfs, "disco/banana"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == db_exists); err = lfsr_remove(&lfs, "disco"); assert(!err || err == LFS_ERR_NOENT); + assert(!err == d_exists); } // remount? @@ -3652,7 +4624,6 @@ code = ''' } // check that our mkdirs worked - struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); @@ -3663,7 +4634,6 @@ code = ''' assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); - lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0);