# Test directory operations after = ['test_mtree', 'test_alloc'] ## mkdir tests [cases.test_dirs_mkdir] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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, "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 that noent errors work [cases.test_dirs_noent] defines.REMOUNT = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; // make a directory lfsr_mkdir(&lfs, "ardvark") => 0; // try to read a nonsense path struct lfs_info info; lfsr_stat(&lfs, "no", &info) => LFS_ERR_NOENT; lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "no") => LFS_ERR_NOENT; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_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, "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 that stat on root works [cases.test_dirs_stat_root] defines.REMOUNT = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; // make a directory lfsr_mkdir(&lfs, "ardvark") => 0; // stat the root struct lfs_info info; lfsr_stat(&lfs, "/", &info) => 0; assert(strcmp(info.name, "/") == 0); assert(info.type == LFS_TYPE_DIR); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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 that creating the same directory twice errors [cases.test_dirs_mkdir_exists] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // make the same directory, should error lfsr_mkdir(&lfs, "ardvark") => LFS_ERR_EXIST; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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_dirs_mkdir_root] 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; } // try to make root, which doesn't make sense err = lfsr_mkdir(&lfs, "/"); assert(err == LFS_ERR_EXIST || err == LFS_ERR_INVAL); // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && 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); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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 that creating a directory with an invalid path errors [cases.test_dirs_mkdir_noent] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // make a nonsense directory, should error lfsr_mkdir(&lfs, "no/hmm") => LFS_ERR_NOENT; // make a nonsense child directory, should error lfsr_mkdir(&lfs, "ardvark/no/hmm") => LFS_ERR_NOENT; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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; ''' [cases.test_dirs_mkdir_siblings] 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; } // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "cat", &info) => 0; 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); 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) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); 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; lfsr_unmount(&lfs) => 0; ''' [cases.test_dirs_mkdir_children] 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; } // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "ardvark/banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 mkdirs worked struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana/cat", &info) => 0; 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); 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_dir_open(&lfs, &dir, "/ardvark") => 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_dir_open(&lfs, &dir, "/ardvark/banana") => 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, "cat") == 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_dirs_mkdir_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 32' 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mkdir_many_backwards] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 32' 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-1-i)); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mkdir_many_2layers] defines.N = [1, 2, 4, 8, 16] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 4' 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 mkdirs worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "child%04d", j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mkdir_many_3layers] defines.N = [1, 2, 4] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 2' 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t k = 0; k < N; k++) { sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 mkdirs worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "grandchild%04d", k); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } } } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "child%04d", j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "grandchild%04d", k); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mkdir_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 16' 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 this many directory in a sort of linked-list by nesting char name[4096]; memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, name) => 0; struct lfs_info info; 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 (i < N-1) { char name2[256]; sprintf(name2, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name2) == 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_dirs_mkdir_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] defines.SEED = 'range(10)' # limit powerloss testing due to time if = '!TEST_PL || N <= 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; } if (PARENT) { err = lfsr_mkdir(&lfs, "pricklypear"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // set up a simulation to compare against lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t sim_size = 0; uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random number, truncate to 4 decimals lfs_size_t x = TEST_PRNG(&prng) % 10000; // insert into our sim for (lfs_size_t j = 0;; j++) { if (j >= sim_size || sim[j] >= x) { // already seen? if (j < sim_size && sim[j] == x) { // do nothing } else { // insert memmove(&sim[j+1], &sim[j], (sim_size-j)*sizeof(lfs_size_t)); sim_size += 1; sim[j] = x; } break; } } // create a directory here char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); int err = lfsr_mkdir(&lfs, name); assert(!err || err == LFS_ERR_EXIST); } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // test that our directories match our simulation for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), sim[j]); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", sim[j]); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "dir%04d", sim[j]); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // clean up sim/lfs free(sim); lfsr_unmount(&lfs) => 0; ''' # test that did collisions don't cause issues [cases.test_dirs_did_collisions] 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; } assert(lfs_crc32c(0, "a_SNmwMTHH", 10) == 0x12345678); assert(lfs_crc32c(0, "b_skvjpWJH", 10) == 0x12345678); assert(lfs_crc32c(0, "c_OnOQhVPH", 10) == 0x12345678); assert(lfs_crc32c(0, "d_puMpPjRH", 10) == 0x12345678); assert(lfs_crc32c(0, "e_LptKHkHH", 10) == 0x12345678); assert(lfs_crc32c(0, "f_lUoVuhJH", 10) == 0x12345678); // make directories err = lfsr_mkdir(&lfs, "a_SNmwMTHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "b_skvjpWJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "c_OnOQhVPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "d_puMpPjRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "e_LptKHkHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "f_lUoVuhJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 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); lfsr_stat(&lfs, "b_skvjpWJH", &info) => 0; assert(strcmp(info.name, "b_skvjpWJH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "c_OnOQhVPH", &info) => 0; assert(strcmp(info.name, "c_OnOQhVPH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "d_puMpPjRH", &info) => 0; assert(strcmp(info.name, "d_puMpPjRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "e_LptKHkHH", &info) => 0; assert(strcmp(info.name, "e_LptKHkHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "f_lUoVuhJH", &info) => 0; 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); 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, "a_SNmwMTHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "b_skvjpWJH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "c_OnOQhVPH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "d_puMpPjRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "e_LptKHkHH") == 0); assert(info.type == LFS_TYPE_DIR); 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; lfsr_unmount(&lfs) => 0; ''' # these will also collide with the root [cases.test_dirs_did_zero] 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; } assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); assert(lfs_crc32c(0, "b_iUwOsqRH", 10) == 0x00000000); assert(lfs_crc32c(0, "c_UPNtkpHH", 10) == 0x00000000); assert(lfs_crc32c(0, "d_jKLUSLJH", 10) == 0x00000000); assert(lfs_crc32c(0, "e_VNunKMPH", 10) == 0x00000000); assert(lfs_crc32c(0, "f_vknsvNRH", 10) == 0x00000000); // make directories err = lfsr_mkdir(&lfs, "a_IplRNrPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "b_iUwOsqRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "c_UPNtkpHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "d_jKLUSLJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "e_VNunKMPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "f_vknsvNRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 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); lfsr_stat(&lfs, "b_iUwOsqRH", &info) => 0; assert(strcmp(info.name, "b_iUwOsqRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "c_UPNtkpHH", &info) => 0; assert(strcmp(info.name, "c_UPNtkpHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "d_jKLUSLJH", &info) => 0; assert(strcmp(info.name, "d_jKLUSLJH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "e_VNunKMPH", &info) => 0; assert(strcmp(info.name, "e_VNunKMPH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "f_vknsvNRH", &info) => 0; 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); 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, "a_IplRNrPH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "b_iUwOsqRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "c_UPNtkpHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "d_jKLUSLJH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "e_VNunKMPH") == 0); assert(info.type == LFS_TYPE_DIR); 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; lfsr_unmount(&lfs) => 0; ''' # these will need to rollover from 0xffffffff -> 0x00000000 correctly # # note this is true even if you truncate [cases.test_dirs_did_ones] 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; } assert(lfs_crc32c(0, "a_iomlVKPH", 10) == 0xffffffff); assert(lfs_crc32c(0, "b_IJvqkHRH", 10) == 0xffffffff); assert(lfs_crc32c(0, "c_uOOJsIHH", 10) == 0xffffffff); assert(lfs_crc32c(0, "d_JTMkKuJH", 10) == 0xffffffff); assert(lfs_crc32c(0, "e_vQtPStPH", 10) == 0xffffffff); assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); // make directories err = lfsr_mkdir(&lfs, "a_iomlVKPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "b_IJvqkHRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "c_uOOJsIHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "d_JTMkKuJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "e_vQtPStPH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "f_VtoMnwRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 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); lfsr_stat(&lfs, "b_IJvqkHRH", &info) => 0; assert(strcmp(info.name, "b_IJvqkHRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "c_uOOJsIHH", &info) => 0; assert(strcmp(info.name, "c_uOOJsIHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "d_JTMkKuJH", &info) => 0; assert(strcmp(info.name, "d_JTMkKuJH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "e_vQtPStPH", &info) => 0; assert(strcmp(info.name, "e_vQtPStPH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "f_VtoMnwRH", &info) => 0; 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); 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, "a_iomlVKPH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "b_IJvqkHRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "c_uOOJsIHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "d_JTMkKuJH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "e_vQtPStPH") == 0); assert(info.type == LFS_TYPE_DIR); 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; lfsr_unmount(&lfs) => 0; ''' # these test some boundary conditions on the underlying leb128 encoding, # if the leb128 disk-size is not calculated correctly these can cause # issues [cases.test_dirs_did_leb128_boundaries] 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; } assert(lfs_crc32c(0, "a_IOtUptRH", 10) == 0x0000007f); assert(lfs_crc32c(0, "b_nquQsKHH", 10) == 0x00000080); assert(lfs_crc32c(0, "c_vwQtKjHH", 10) == 0x00000081); assert(lfs_crc32c(0, "d_sVrvrWHH", 10) == 0x00003fff); assert(lfs_crc32c(0, "e_thrRIsRH", 10) == 0x00004000); assert(lfs_crc32c(0, "f_pNtQTPJH", 10) == 0x00004001); // make directories err = lfsr_mkdir(&lfs, "a_IOtUptRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "b_nquQsKHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "c_vwQtKjHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "d_sVrvrWHH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "e_thrRIsRH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "f_pNtQTPJH"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 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); lfsr_stat(&lfs, "b_nquQsKHH", &info) => 0; assert(strcmp(info.name, "b_nquQsKHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "c_vwQtKjHH", &info) => 0; assert(strcmp(info.name, "c_vwQtKjHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "d_sVrvrWHH", &info) => 0; assert(strcmp(info.name, "d_sVrvrWHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "e_thrRIsRH", &info) => 0; assert(strcmp(info.name, "e_thrRIsRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "f_pNtQTPJH", &info) => 0; 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); 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, "a_IOtUptRH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "b_nquQsKHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "c_vwQtKjHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "d_sVrvrWHH") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "e_thrRIsRH") == 0); assert(info.type == LFS_TYPE_DIR); 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; lfsr_unmount(&lfs) => 0; ''' ## dir remove tests [cases.test_dirs_rm] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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, "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 that noent errors work [cases.test_dirs_rm_noent] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to remove a nonsense directory lfsr_remove(&lfs, "no") => LFS_ERR_NOENT; // try to remove a directory in a nonsense directory lfsr_remove(&lfs, "no/ardvark") => LFS_ERR_NOENT; // try to remove a nonsense child directory lfsr_remove(&lfs, "ardvark/no") => LFS_ERR_NOENT; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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 that we catch removing of a non-empty directory [cases.test_dirs_rm_notempty] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // fill it with stuff err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to remove the parent directory lfsr_remove(&lfs, "ardvark") => LFS_ERR_NOTEMPTY; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana", &info) => 0; assert(strcmp(info.name, "banana") == 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); 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_dir_open(&lfs, &dir, "ardvark") => 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 remove root [cases.test_dirs_rm_root] 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; } // try to remove root, which doesn't really make sense lfsr_remove(&lfs, "/") => LFS_ERR_INVAL; // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to remove root, which doesn't really make sense // // it doesn't really matter which error returns first, so accept both err = lfsr_remove(&lfs, "/"); assert(err == LFS_ERR_NOTEMPTY || err == LFS_ERR_INVAL); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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; ''' [cases.test_dirs_rm_siblings] 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; } // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "cat", &info) => 0; 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); 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) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); 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; // now remove each 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 our remove worked 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); lfsr_stat(&lfs, "cat", &info) => 0; assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_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, "banana") == 0); assert(info.type == LFS_TYPE_DIR); 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; // remove another lfsr_remove(&lfs, "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 our remove worked lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "banana", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "cat", &info) => 0; assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_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, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // remove another lfsr_remove(&lfs, "cat") => 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 our remove worked lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "banana", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "cat", &info) => LFS_ERR_NOENT; 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_dirs_rm_children] 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; } // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "ardvark/banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 mkdirs worked struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana/cat", &info) => 0; 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); 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_dir_open(&lfs, &dir, "/ardvark") => 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_dir_open(&lfs, &dir, "/ardvark/banana") => 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, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // now remove each directory lfsr_remove(&lfs, "ardvark/banana/cat") => 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 our remove worked lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana/cat", &info) => LFS_ERR_NOENT; 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_dir_open(&lfs, &dir, "/ardvark") => 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_dir_open(&lfs, &dir, "/ardvark/banana") => 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; // remove another lfsr_remove(&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 our remove worked lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "ardvark/banana/cat", &info) => LFS_ERR_NOENT; 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_dir_open(&lfs, &dir, "/ardvark") => 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; // remove another 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 our remove worked lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "ardvark/banana", &info) => LFS_ERR_NOENT; lfsr_stat(&lfs, "ardvark/banana/cat", &info) => LFS_ERR_NOENT; 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_dirs_rm_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMAINING = [64, 2, 1, 0] defines.REMOUNT = [false, true] if = [ 'N > REMAINING', # limit powerloss testing due to time '!TEST_PL || N <= 32', ] 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // 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 for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // now remove some number of directories for (lfs_size_t i = 0; i < N-REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_remove(&lfs, name) => 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 our removes worked for (lfs_size_t i = 0; i < N-REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-REMAINING + i)); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_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); for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-REMAINING + i)); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_rm_many_backwards] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMAINING = [64, 2, 1, 0] defines.REMOUNT = [false, true] if = [ 'N > REMAINING', # limit powerloss testing due to time '!TEST_PL || N <= 32', ] 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-1-i)); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // 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 for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // now remove some number of directories for (lfs_size_t i = 0; i < N-REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-1-i)); lfsr_remove(&lfs, name) => 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 our removes worked for (lfs_size_t i = 0; i < N-REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-1-i)); struct lfs_info info; lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_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); for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_rm_many_2layers] defines.N = [1, 2, 4, 8, 16] defines.REMAINING = [2, 1, 0] defines.REMOUNT = [false, true] if = [ 'N > REMAINING', # limit powerloss testing due to time '!TEST_PL || N <= 4', ] 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } } // 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 mkdirs worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "child%04d", j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } // now remove some number of directories for (lfs_size_t i = 0; i < N; i++) { for (lfs_size_t j = 0; j < N; j++) { if (i < N-REMAINING || j < N-REMAINING) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); lfsr_remove(&lfs, name) => 0; } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } } if (i < N-REMAINING) { char name[256]; sprintf(name, "dir%04d", i); lfsr_remove(&lfs, name) => 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 our removes worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; if (i < N-REMAINING) { lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } else { lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; if (j < N-REMAINING) { lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } else { lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_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); for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-REMAINING + i)); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-REMAINING + i)); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < REMAINING; j++) { char name[256]; sprintf(name, "child%04d", (int)(N-REMAINING + j)); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_rm_many_3layers] defines.N = [1, 2, 4] defines.REMAINING = [2, 1, 0] defines.REMOUNT = [false, true] if = [ 'N > REMAINING', # limit powerloss testing due to time '!TEST_PL || N <= 2', ] 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; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t k = 0; k < N; k++) { sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } } } // 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 mkdirs worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "grandchild%04d", k); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } } } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "child%04d", j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "grandchild%04d", k); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } } // now remove some number of directories for (lfs_size_t i = 0; i < N; i++) { for (lfs_size_t j = 0; j < N; j++) { for (lfs_size_t k = 0; k < N; k++) { if (i < N-REMAINING || j < N-REMAINING || k < N-REMAINING) { char name[256]; sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); lfsr_remove(&lfs, name) => 0; } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } } if (i < N-REMAINING || j < N-REMAINING) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); lfsr_remove(&lfs, name) => 0; } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } } if (i < N-REMAINING) { char name[256]; sprintf(name, "dir%04d", i); lfsr_remove(&lfs, name) => 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 our removes worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; if (i < N-REMAINING) { lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } else { lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; if (j < N-REMAINING) { lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } else { lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); struct lfs_info info; if (k < N-REMAINING) { lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } else { lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "grandchild%04d", k); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_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); for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-REMAINING + i)); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < REMAINING; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-REMAINING + i)); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < REMAINING; j++) { char name[256]; sprintf(name, "child%04d", (int)(N-REMAINING + j)); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } for (lfs_size_t i = 0; i < REMAINING; i++) { for (lfs_size_t j = 0; j < REMAINING; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", (int)(N-REMAINING + i), (int)(N-REMAINING + j)); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t k = 0; k < REMAINING; k++) { char name[256]; sprintf(name, "grandchild%04d", (int)(N-REMAINING + k)); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_rm_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.REMAINING = [16, 2, 1, 0] defines.REMOUNT = [false, true] if = [ 'N > REMAINING', # limit powerloss testing due to time '!TEST_PL || N <= 16', ] 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 this many directory in a sort of linked-list by nesting char name[4096]; memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // 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 memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, name) => 0; struct lfs_info info; 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 (i < N-1) { char name2[256]; sprintf(name2, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } // now remove some number of directories for (lfs_size_t i = 0; i < N-REMAINING; i++) { lfsr_remove(&lfs, name) => 0; name[strlen(name) - strlen("/dir....")] = '\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 our remove worked memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < REMAINING; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < REMAINING; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, name) => 0; struct lfs_info info; 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 (i < REMAINING-1) { char name2[256]; sprintf(name2, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name2) == 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_dirs_rm_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] defines.SEED = 'range(10)' # limit powerloss testing due to time if = '!TEST_PL || N <= 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; } if (PARENT) { err = lfsr_mkdir(&lfs, "pricklypear"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // set up a simulation to compare against lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t sim_size = 0; uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random op, either mkdir or rmdir uint8_t op = TEST_PRNG(&prng) % 2; if (op == 0 || sim_size == 0) { // choose a pseudo-random number, truncate to 4 decimals lfs_size_t x = TEST_PRNG(&prng) % 10000; // insert into our sim for (lfs_size_t j = 0;; j++) { if (j >= sim_size || sim[j] >= x) { // already seen? if (j < sim_size && sim[j] == x) { // do nothing } else { // insert memmove(&sim[j+1], &sim[j], (sim_size-j)*sizeof(lfs_size_t)); sim_size += 1; sim[j] = x; } break; } } // create a directory here char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); int err = lfsr_mkdir(&lfs, name); assert(!err || err == LFS_ERR_EXIST); } else { // choose a pseudo-random entry to delete lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t x = sim[j]; // delete from our sim memmove(&sim[j], &sim[j+1], (sim_size-(j+1))*sizeof(lfs_size_t)); sim_size -= 1; // remove this directory char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); lfsr_remove(&lfs, name) => 0; } } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // test that our directories match our simulation for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), sim[j]); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", sim[j]); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "dir%04d", sim[j]); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // clean up sim/lfs free(sim); lfsr_unmount(&lfs) => 0; ''' ## dir rename tests [cases.test_dirs_mv] 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; } // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // clean up interrupted renames if (TEST_PL) { err = lfsr_remove(&lfs, "banana"); assert(!err || err == LFS_ERR_NOENT); } // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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, "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 that we can rename, and replace, other directories [cases.test_dirs_mv_replace] 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; } // make directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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, "ardvark") == 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; // 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 that we can rename to ourselves [cases.test_dirs_mv_noop] 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; } // make directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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, "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 to itself lfsr_rename(&lfs, "ardvark", "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 rename 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 that we catch replacing an invalid path [cases.test_dirs_mv_noent] 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; } // make directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to rename a nonsense directory lfsr_rename(&lfs, "no", "ardvark") => LFS_ERR_NOENT; // try to rename a directory in a nonsense directory lfsr_rename(&lfs, "no/ardvark", "ardvark") => LFS_ERR_NOENT; // try to rename a nonsense child directory lfsr_rename(&lfs, "ardvark/no", "banana") => LFS_ERR_NOENT; // try to rename to a nonense directory lfsr_rename(&lfs, "ardvark", "no/ardvark") => LFS_ERR_NOENT; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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 that we catch replacing a non-empty directory [cases.test_dirs_mv_notempty] 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; } // make directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // fill dest with stuff err = lfsr_mkdir(&lfs, "banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to rename lfsr_rename(&lfs, "ardvark", "banana") => LFS_ERR_NOTEMPTY; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "banana/cat", &info) => 0; 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); 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) => 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_dir_open(&lfs, &dir, "banana") => 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, "cat") == 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_dirs_mv_root] 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; } // try to rename root, which doesn't really make sense lfsr_rename(&lfs, "/", "notroot") => LFS_ERR_INVAL; // make a directory err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // try to rename root, which doesn't really make sense lfsr_rename(&lfs, "/", "notroot") => LFS_ERR_INVAL; // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // and check that this didn't interfere with our original directory struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 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); 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; ''' [cases.test_dirs_mv_siblings] 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; } // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // clean up interrupted renames if (TEST_PL) { err = lfsr_remove(&lfs, "disco"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "eggplant"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "fish"); assert(!err || err == LFS_ERR_NOENT); } // 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 struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "cat", &info) => 0; 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); 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) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); 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; // now rename each directory lfsr_rename(&lfs, "ardvark", "disco") => 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 our rename worked lfsr_stat(&lfs, "banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "cat", &info) => 0; assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco", &info) => 0; assert(strcmp(info.name, "disco") == 0); assert(info.type == LFS_TYPE_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, "banana") == 0); assert(info.type == LFS_TYPE_DIR); 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) => 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; // rename another lfsr_rename(&lfs, "banana", "eggplant") => 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 our rename worked lfsr_stat(&lfs, "cat", &info) => 0; assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco", &info) => 0; assert(strcmp(info.name, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "eggplant", &info) => 0; assert(strcmp(info.name, "eggplant") == 0); assert(info.type == LFS_TYPE_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, "cat") == 0); assert(info.type == LFS_TYPE_DIR); 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) => 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; // rename another lfsr_rename(&lfs, "cat", "fish") => 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 our rename worked lfsr_stat(&lfs, "disco", &info) => 0; assert(strcmp(info.name, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "eggplant", &info) => 0; assert(strcmp(info.name, "eggplant") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "fish", &info) => 0; assert(strcmp(info.name, "fish") == 0); assert(info.type == LFS_TYPE_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, "disco") == 0); assert(info.type == LFS_TYPE_DIR); 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) => 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; lfsr_unmount(&lfs) => 0; ''' [cases.test_dirs_mv_children] 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; } // make some directories err = lfsr_mkdir(&lfs, "ardvark"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "ardvark/banana"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); err = lfsr_mkdir(&lfs, "ardvark/banana/cat"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // clean up interrupted renames if (TEST_PL) { err = lfsr_remove(&lfs, "disco/eggplant/fish"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "disco/eggplant/cat"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "disco/eggplant"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "disco/banana/cat"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "disco/banana"); assert(!err || err == LFS_ERR_NOENT); err = lfsr_remove(&lfs, "disco"); assert(!err || err == LFS_ERR_NOENT); } // 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 mkdirs worked struct lfs_info info; lfsr_stat(&lfs, "ardvark", &info) => 0; assert(strcmp(info.name, "ardvark") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "ardvark/banana/cat", &info) => 0; 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); 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_dir_open(&lfs, &dir, "/ardvark") => 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_dir_open(&lfs, &dir, "/ardvark/banana") => 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, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // now rename each directory lfsr_rename(&lfs, "ardvark", "disco") => 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 our rename worked lfsr_stat(&lfs, "disco", &info) => 0; assert(strcmp(info.name, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco/banana", &info) => 0; assert(strcmp(info.name, "banana") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco/banana/cat", &info) => 0; assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_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, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_open(&lfs, &dir, "/disco") => 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_dir_open(&lfs, &dir, "/disco/banana") => 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, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // rename another lfsr_rename(&lfs, "disco/banana", "disco/eggplant") => 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 our rename worked lfsr_stat(&lfs, "disco", &info) => 0; assert(strcmp(info.name, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco/eggplant", &info) => 0; assert(strcmp(info.name, "eggplant") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco/eggplant/cat", &info) => 0; assert(strcmp(info.name, "cat") == 0); assert(info.type == LFS_TYPE_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, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_open(&lfs, &dir, "/disco") => 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, "eggplant") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_open(&lfs, &dir, "/disco/eggplant") => 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, "cat") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // rename another lfsr_rename(&lfs, "disco/eggplant/cat", "disco/eggplant/fish") => 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 our rename worked lfsr_stat(&lfs, "disco", &info) => 0; assert(strcmp(info.name, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco/eggplant", &info) => 0; assert(strcmp(info.name, "eggplant") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_stat(&lfs, "disco/eggplant/fish", &info) => 0; assert(strcmp(info.name, "fish") == 0); assert(info.type == LFS_TYPE_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, "disco") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_open(&lfs, &dir, "/disco") => 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, "eggplant") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_open(&lfs, &dir, "/disco/eggplant") => 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, "fish") == 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_dirs_mv_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 32' 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 we have already started renaming, in case of powerloss struct lfs_info info; err = lfsr_stat(&lfs, (BEFORE ? "/0mved0000" : "/mved0000"), &info); if (err == LFS_ERR_NOENT) { // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // 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 for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 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 directories for (lfs_size_t i = 0; i < N; i++) { char old_name[256]; sprintf(old_name, "dir%04d", i); char new_name[256]; sprintf(new_name, "%smved%04d", (BEFORE ? "0" : ""), i); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // 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 renames worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 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); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mv_many_backwards] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 32' 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 we have already started renaming, in case of powerloss struct lfs_info info; err = lfsr_stat(&lfs, (BEFORE ? "/0mved0000" : "/mved0000"), &info); if (err == LFS_ERR_NOENT) { // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", (int)(N-1-i)); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // 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 for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 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 directories for (lfs_size_t i = 0; i < N; i++) { char old_name[256]; sprintf(old_name, "dir%04d", i); char new_name[256]; sprintf(new_name, "%smved%04d", (BEFORE ? "0" : ""), i); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // 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 renames worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 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); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mv_many_2layers] defines.N = [1, 2, 4, 8, 16] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 4' 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 we have already started renaming, in case of powerloss struct lfs_info info; err = lfsr_stat(&lfs, (BEFORE ? "/0mved0000" : "/mved0000"), &info); if (err == LFS_ERR_NOENT) { // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } } // 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 mkdirs worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "child%04d", j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } } // now rename our directories for (lfs_size_t i = 0; i < N; i++) { char old_name[256]; sprintf(old_name, "dir%04d", i); char new_name[256]; sprintf(new_name, "%smved%04d", (BEFORE ? "0" : ""), i); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } for (lfs_size_t j = 0; j < N; j++) { char old_name[256]; sprintf(old_name, "%smved%04d/child%04d", (BEFORE ? "0" : ""), i, j); char new_name[256]; sprintf(new_name, "%smved%04d/%schmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // 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 renames worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "%smved%04d/%schmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "%schmved%04d", (BEFORE ? "0" : ""), j); assert(strcmp(info.name, name) == 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); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "%schmved%04d", (BEFORE ? "0" : ""), j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mv_many_3layers] defines.N = [1, 2, 4] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 2' 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 we have already started renaming, in case of powerloss struct lfs_info info; err = lfsr_stat(&lfs, (BEFORE ? "/0mved0000" : "/mved0000"), &info); if (err == LFS_ERR_NOENT) { // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t j = 0; j < N; j++) { sprintf(name, "dir%04d/child%04d", i, j); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); // containing this many directories for (lfs_size_t k = 0; k < N; k++) { sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } } } // 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 mkdirs worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "child%04d", j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "grandchild%04d", k); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } } } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "child%04d", j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "dir%04d/child%04d", i, j); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "grandchild%04d", k); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } } } // now rename our directories for (lfs_size_t i = 0; i < N; i++) { char old_name[256]; sprintf(old_name, "dir%04d", i); char new_name[256]; sprintf(new_name, "%smved%04d", (BEFORE ? "0" : ""), i); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } for (lfs_size_t j = 0; j < N; j++) { char old_name[256]; sprintf(old_name, "%smved%04d/child%04d", (BEFORE ? "0" : ""), i, j); char new_name[256]; sprintf(new_name, "%smved%04d/%schmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } for (lfs_size_t k = 0; k < N; k++) { char old_name[256]; sprintf(old_name, "%smved%04d/%schmved%04d/grandchild%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j, k); char new_name[256]; sprintf(new_name, "%smved%04d/%schmved%04d/%sgrmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j, (BEFORE ? "0" : ""), k); int err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // 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 removes worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "%smved%04d/%schmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "%schmved%04d", (BEFORE ? "0" : ""), j); assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "%smved%04d/%schmved%04d/%sgrmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j, (BEFORE ? "0" : ""), k); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; sprintf(name, "%sgrmved%04d", (BEFORE ? "0" : ""), k); assert(strcmp(info.name, name) == 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); assert(info.type == LFS_TYPE_DIR); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "%schmved%04d", (BEFORE ? "0" : ""), j); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; for (lfs_size_t j = 0; j < N; j++) { char name[256]; sprintf(name, "%smved%04d/%schmved%04d", (BEFORE ? "0" : ""), i, (BEFORE ? "0" : ""), j); lfsr_dir_open(&lfs, &dir, name) => 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); for (lfs_size_t k = 0; k < N; k++) { char name[256]; sprintf(name, "%sgrmved%04d", (BEFORE ? "0" : ""), k); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_mv_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] # limit powerloss testing due to time if = '!TEST_PL || N <= 16' 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 we have already started renaming, in case of powerloss struct lfs_info info; err = lfsr_stat(&lfs, (BEFORE ? "/0mved0000" : "/mved0000"), &info); if (err == LFS_ERR_NOENT) { // create this many directory in a sort of linked-list by nesting char name[4096]; memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // 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 memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, name) => 0; struct lfs_info info; 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 (i < N-1) { char name2[256]; sprintf(name2, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } } // now rename our directories char old_name[4096]; memset(old_name, 0, sizeof(old_name)); char new_name[4096]; memset(new_name, 0, sizeof(new_name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&old_name[strlen(old_name)], "/dir%04d", i); sprintf(&new_name[strlen(new_name)], "/%smved%04d", (BEFORE ? "0" : ""), i); err = lfsr_rename(&lfs, old_name, new_name); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // update old_name's path memcpy(old_name, new_name, sizeof(old_name)); } // check that our renames worked char name[4096]; memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/%smved%04d", (BEFORE ? "0" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "%smved%04d", (BEFORE ? "0" : ""), i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, name) => 0; struct lfs_info info; 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 (i < N-1) { char name2[256]; sprintf(name2, "%smved%04d", (BEFORE ? "0" : ""), i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name2) == 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_dirs_mv_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] defines.SEED = 'range(10)' # limit powerloss testing due to time if = '!TEST_PL || N <= 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; } if (PARENT) { err = lfsr_mkdir(&lfs, "pricklypear"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // set up a simulation to compare against lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t sim_size = 0; uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random op, either mkdir or rename uint8_t op = TEST_PRNG(&prng) % 2; if (op == 0 || sim_size == 0) { // choose a pseudo-random number, truncate to 4 decimals lfs_size_t x = TEST_PRNG(&prng) % 10000; // insert into our sim for (lfs_size_t j = 0;; j++) { if (j >= sim_size || sim[j] >= x) { // already seen? if (j < sim_size && sim[j] == x) { // do nothing } else { // insert memmove(&sim[j+1], &sim[j], (sim_size-j)*sizeof(lfs_size_t)); sim_size += 1; sim[j] = x; } break; } } // create a directory here char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); int err = lfsr_mkdir(&lfs, name); assert(!err || err == LFS_ERR_EXIST); } else { // choose a pseudo-random entry to rename, and a pseudo-random // number to rename to lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t x = sim[j]; lfs_size_t y = TEST_PRNG(&prng) % 10000; for (lfs_size_t k = 0;; k++) { if (k >= sim_size || sim[k] >= y) { // already seen and not a noop? if (k < sim_size && sim[k] == y && x != y) { // just delete the original entry memmove(&sim[j], &sim[j+1], (sim_size-(j+1))*sizeof(lfs_size_t)); sim_size -= 1; } else { // first delete memmove(&sim[j], &sim[j+1], (sim_size-(j+1))*sizeof(lfs_size_t)); if (k > j) { k -= 1; } // then insert memmove(&sim[k+1], &sim[k], (sim_size-k)*sizeof(lfs_size_t)); sim[k] = y; } break; } } // rename this directory char old_name[256]; sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); char new_name[256]; sprintf(new_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), y); lfsr_rename(&lfs, old_name, new_name) => 0; } } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // test that our directories match our simulation for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), sim[j]); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", sim[j]); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "dir%04d", sim[j]); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // clean up sim/lfs free(sim); lfsr_unmount(&lfs) => 0; ''' # test all of the operations together [cases.test_dirs_general_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] defines.SEED = 'range(10)' # limit powerloss testing due to time if = '!TEST_PL || N <= 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; } if (PARENT) { err = lfsr_mkdir(&lfs, "pricklypear"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // set up a simulation to compare against lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t sim_size = 0; uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random op, either mkdir, remove, or rename uint8_t op = TEST_PRNG(&prng) % 3; if (op == 0 || sim_size == 0) { // choose a pseudo-random number, truncate to 4 decimals lfs_size_t x = TEST_PRNG(&prng) % 10000; // insert into our sim for (lfs_size_t j = 0;; j++) { if (j >= sim_size || sim[j] >= x) { // already seen? if (j < sim_size && sim[j] == x) { // do nothing } else { // insert memmove(&sim[j+1], &sim[j], (sim_size-j)*sizeof(lfs_size_t)); sim_size += 1; sim[j] = x; } break; } } // create a directory here char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); int err = lfsr_mkdir(&lfs, name); assert(!err || err == LFS_ERR_EXIST); } else if (op == 1) { // choose a pseudo-random entry to delete lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t x = sim[j]; // delete from our sim memmove(&sim[j], &sim[j+1], (sim_size-(j+1))*sizeof(lfs_size_t)); sim_size -= 1; // remove this directory char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); lfsr_remove(&lfs, name) => 0; } else { // choose a pseudo-random entry to rename, and a pseudo-random // number to rename to lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t x = sim[j]; lfs_size_t y = TEST_PRNG(&prng) % 10000; for (lfs_size_t k = 0;; k++) { if (k >= sim_size || sim[k] >= y) { // already seen and not a noop? if (k < sim_size && sim[k] == y && x != y) { // just delete the original entry memmove(&sim[j], &sim[j+1], (sim_size-(j+1))*sizeof(lfs_size_t)); sim_size -= 1; } else { // first delete memmove(&sim[j], &sim[j+1], (sim_size-(j+1))*sizeof(lfs_size_t)); if (k > j) { k -= 1; } // then insert memmove(&sim[k+1], &sim[k], (sim_size-k)*sizeof(lfs_size_t)); sim[k] = y; } break; } } // rename this directory char old_name[256]; sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x); char new_name[256]; sprintf(new_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), y); lfsr_rename(&lfs, old_name, new_name) => 0; } } // remount? if (REMOUNT) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, cfg) => 0; // grm should be zero here assert(lfs.pgrm[0] == 0); } // test that our directories match our simulation for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), sim[j]); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", sim[j]); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); for (lfs_size_t j = 0; j < sim_size; j++) { char name[256]; sprintf(name, "dir%04d", sim[j]); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // clean up sim/lfs free(sim); lfsr_unmount(&lfs) => 0; ''' ## Test seeking and stuff [cases.test_dirs_tell] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } // read our directory // // Note tell's value is not guaranteed! We can test the exact value only // because these tests are tightly bound to the current littlefs version. // lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; lfsr_dir_tell(&lfs, &dir) => 0; struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_tell(&lfs, &dir) => 1; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_tell(&lfs, &dir) => 2 + i; char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_tell(&lfs, &dir) => 2 + N; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_tell(&lfs, &dir) => 2 + N; lfsr_dir_close(&lfs, &dir) => 0; lfsr_unmount(&lfs) => 0; ''' [cases.test_dirs_rewind] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; // read our directory once lfsr_dir_tell(&lfs, &dir) => 0;; struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_tell(&lfs, &dir) => 1; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_tell(&lfs, &dir) => 2 + i; char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_tell(&lfs, &dir) => 2 + N; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_tell(&lfs, &dir) => 2 + N; // now read it again lfsr_dir_rewind(&lfs, &dir) => 0; lfsr_dir_tell(&lfs, &dir) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_tell(&lfs, &dir) => 1; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_tell(&lfs, &dir) => 2 + i; char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_tell(&lfs, &dir) => 2 + N; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_tell(&lfs, &dir) => 2 + N; lfsr_dir_close(&lfs, &dir) => 0; lfsr_unmount(&lfs) => 0; ''' [cases.test_dirs_seek] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; // read our directory once lfsr_dir_tell(&lfs, &dir) => 0; struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_tell(&lfs, &dir) => 1; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_tell(&lfs, &dir) => 2 + i; char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_tell(&lfs, &dir) => 2 + N; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_tell(&lfs, &dir) => 2 + N; // now try to seek to each entry explicitly lfsr_dir_seek(&lfs, &dir, 0) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); lfsr_dir_seek(&lfs, &dir, 1) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (lfs_size_t i = 0; i < N; i++) { lfsr_dir_seek(&lfs, &dir, 2 + i) => 0; char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_seek(&lfs, &dir, 2 + N) => 0; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_seek(&lfs, &dir, 2 + N) => 0; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_unmount(&lfs) => 0; ''' [cases.test_dirs_read_idempotent] defines.PARENT = [false, true] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # neighbors only make sense if we have a parent if = 'PARENT || NEIGHBORS == 0' code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } } char name[256]; sprintf(name, "%s/ardvark", (PARENT ? "pricklypear" : "")); lfsr_mkdir(&lfs, name) => 0; // read to the end lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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_tell(&lfs, &dir) => 3; // reading again should still return noent lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; // seeking past the end of the directory should still return noent lfsr_dir_seek(&lfs, &dir, 3) => 0; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_seek(&lfs, &dir, 4) => 0; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_seek(&lfs, &dir, 1000) => 0; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; // but we should be able to read again lfsr_dir_rewind(&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; ''' [cases.test_dirs_read_with_mkdirs] defines.N = 5 # where in the dir read do we mkdir? defines.I = 'range(6)' # where do we mkdir? defines.J = 'range(6)' defines.PARENT = [false, true] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] # neighbors only make sense if we have a parent if = 'PARENT || NEIGHBORS == 0' code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i+1); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // make a dir at J char name[256]; sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)J); lfsr_mkdir(&lfs, name) => 0; // seek after mkdir? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // we should be able to keep reading, though we may pick up J for (lfs_size_t i = I + (I >= J ? 1 : 0); i < N+1; i++) { char name[256]; sprintf(name, "dir%04d%s", i+1 - (i >= J ? 1 : 0), (i == J ? "_" : "")); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_read_with_rms] defines.N = 5 # where in the dir read do we rm? defines.I = 'range(5)' # where do we rm? defines.J = 'range(5)' defines.PARENT = [false, true] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] # neighbors only make sense if we have a parent if = 'PARENT || NEIGHBORS == 0' code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // remove the dir at J char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); lfsr_remove(&lfs, name) => 0; // seek after remove? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // we should be able to keep reading for (lfs_size_t i = I; i < N; i++) { if (i == J) { continue; } char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_read_with_mvs] defines.N = 5 # where in the dir read do we rm? defines.I = 'range(5)' # where do we rm? defines.J = 'range(5)' defines.K = 'range(5)' defines.BEFORE = [false, true] # 0 => no # 1 => yes # 2 => yes, and rename to new parent defines.PARENT = [0, 1, 2] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] # neighbors only make sense if we have a parent if = 'PARENT || NEIGHBORS == 0' code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (PARENT >= 2) { lfsr_mkdir(&lfs, "quiabentia") => 0; } if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // rename the dir at J char old_name[256]; sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); char new_name[256]; sprintf(new_name, "%s/%smved%04d", (PARENT == 1 ? "pricklypear" : PARENT >= 2 ? "quiabentia" : ""), (BEFORE ? "0" : ""), (int)J); lfsr_rename(&lfs, old_name, new_name) => 0; // seek after remove? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // we should be able to keep reading for (lfs_size_t i = I; i < N; i++) { if (i == J) { continue; } char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } int err = lfsr_dir_read(&lfs, &dir, &info); assert(err == LFS_ERR_NOENT || (!BEFORE && PARENT < 2)); lfsr_dir_close(&lfs, &dir) => 0; lfsr_unmount(&lfs) => 0; ''' # dir reads with 2x ops have better chances of catching bugs that depend on # invalid dir states [cases.test_dirs_read_with_2_mkdirs] defines.N = 5 # where in the dir read do we mkdir? defines.I = 'range(6)' # where do we mkdir? defines.J = 'range(6)' defines.K = 'range(6)' defines.PARENT = [false, true] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] if = [ 'J != K', # neighbors only make sense if we have a parent 'PARENT || NEIGHBORS == 0', ] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; } } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i+1); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // make a dir at J char name[256]; sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)J); lfsr_mkdir(&lfs, name) => 0; // make a dir at K sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)K); lfsr_mkdir(&lfs, name) => 0; // seek after mkdir? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // we should be able to keep reading, though we may pick up J for (lfs_size_t i = I + (I >= J ? 1 : 0) + (I >= K ? 1 : 0); i < N+2; i++) { char name[256]; sprintf(name, "dir%04d%s", i+1 - (i >= J + (J >= K ? 1 : 0) ? 1 : 0) - (i >= K + (K >= J ? 1 : 0) ? 1 : 0), (i == J + (J > K ? 1 : 0) || i == K + (K > J ? 1 : 0) ? "_" : "")); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_read_with_2_rms] defines.N = 5 # where in the dir read do we rm? defines.I = 'range(5)' # where do we rm? defines.J = 'range(5)' defines.K = 'range(5)' defines.PARENT = [false, true] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] if = [ 'J != K', # neighbors only make sense if we have a parent 'PARENT || NEIGHBORS == 0', ] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // remove the dir at J char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); lfsr_remove(&lfs, name) => 0; // remove the dir at K sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)K); lfsr_remove(&lfs, name) => 0; // seek after remove? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // we should be able to keep reading for (lfs_size_t i = I; i < N; i++) { if (i == J || i == K) { continue; } char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_read_with_2_mvs] defines.N = 5 # where in the dir read do we rm? defines.I = 'range(5)' # where do we rm? defines.J = 'range(5)' defines.K = 'range(5)' defines.BEFORE = [false, true] # 0 => no # 1 => yes # 2 => yes, and rename to new parent defines.PARENT = [0, 1, 2] # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] # neighbors only make sense if we have a parent if = [ 'J != K', # neighbors only make sense if we have a parent 'PARENT || NEIGHBORS == 0', ] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; if (PARENT) { lfsr_mkdir(&lfs, "pricklypear") => 0; if (PARENT >= 2) { lfsr_mkdir(&lfs, "quiabentia") => 0; } if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // rename the dir at J char old_name[256]; sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); char new_name[256]; sprintf(new_name, "%s/%smved%04d", (PARENT == 1 ? "pricklypear" : PARENT >= 2 ? "quiabentia" : ""), (BEFORE ? "0" : ""), (int)J); lfsr_rename(&lfs, old_name, new_name) => 0; // rename the dir at K sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)K); sprintf(new_name, "%s/%smved%04d", (PARENT == 1 ? "pricklypear" : PARENT >= 2 ? "quiabentia" : ""), (BEFORE ? "0" : ""), (int)K); lfsr_rename(&lfs, old_name, new_name) => 0; // seek after remove? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // we should be able to keep reading for (lfs_size_t i = I; i < N; i++) { if (i == J || i == K) { continue; } char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } int err = lfsr_dir_read(&lfs, &dir, &info); assert(err == LFS_ERR_NOENT || (!BEFORE && PARENT < 2)); lfsr_dir_close(&lfs, &dir) => 0; lfsr_unmount(&lfs) => 0; ''' # test removing the directory we are iterating over [cases.test_dirs_read_rm] defines.N = 5 # where in the dir read do we remove? defines.I = 'range(6)' # bit 0x2 = left neighbor # bit 0x1 = right neighbor defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] code = ''' lfs_t lfs; lfsr_format(&lfs, cfg) => 0; lfsr_mount(&lfs, cfg) => 0; lfsr_mkdir(&lfs, "pricklypear") => 0; if (NEIGHBORS & 0x2) { assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; } if (NEIGHBORS & 0x1) { assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; } // create our directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "pricklypear/dir%04d", i+1); lfsr_mkdir(&lfs, name) => 0; } // start reading lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "pricklypear") => 0; struct lfs_info info; 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); // read until I for (lfs_size_t i = 0; i < I; i++) { char name[256]; sprintf(name, "dir%04d", i+1); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } // remove the directory for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "pricklypear/dir%04d", i+1); lfsr_remove(&lfs, name) => 0; } lfsr_remove(&lfs, "pricklypear") => 0; // seek after mkdir? if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } // try to read, but this should return an error lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; lfsr_unmount(&lfs) => 0; ''' ## Recursive tests # Recursive here just refers to removing entries in a directory while # iterating over the directory # # This is a useful feature, but it's unintuitive if this should have # well-defined behavior, so make sure to test for it [cases.test_dirs_recursive_rm] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] # limit powerloss testing due to time if = '!TEST_PL || N <= 32' 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; } if (PARENT) { err = lfsr_mkdir(&lfs, "pricklypear"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // check that our mkdir worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // now remove directories recursively lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); char path[1024]; sprintf(path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); lfsr_remove(&lfs, path) => 0; // seek between removes? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; // check that our removes worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; } lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 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; ''' # Recursive here just refers to renaming entries in a directory while # iterating over the directory # # This is a useful feature, but it's unintuitive if this should have # well-defined behavior, so make sure to test for it [cases.test_dirs_recursive_mv] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.BEFORE = [false, true] # 0 => no # 1 => yes # 2 => yes, and rename to new parent defines.PARENT = [0, 1, 2] # 0 => don't seek # 1 => seek # 2 => rewind then seek defines.SEEK = [0, 1, 2] # limit powerloss testing due to time if = '!TEST_PL || N <= 32' 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; } if (PARENT) { err = lfsr_mkdir(&lfs, "pricklypear"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); if (PARENT >= 2) { err = lfsr_mkdir(&lfs, "quiabentia"); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } } // check if we have already started renaming, in case of powerloss struct lfs_info info; err = lfsr_stat(&lfs, (PARENT == 1 ? (BEFORE ? "pricklypear/0mved0000" : "pricklypear/mved0000") : PARENT >= 2 ? (BEFORE ? "quiabentia/0mved0000" : "quiabentia/mved0000") : (BEFORE ? "/0mved0000" : "/mved0000")), &info); if (err == LFS_ERR_NOENT) { // make this many directories for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); err = lfsr_mkdir(&lfs, name); assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); } // check that our mkdir worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "dir%04d", i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; struct lfs_info info; 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "dir%04d", i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, name) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_close(&lfs, &dir) => 0; } // now rename directories recursively lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 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); for (lfs_size_t i = 0;; i++) { int err = lfsr_dir_read(&lfs, &dir, &info); assert(!err || err == LFS_ERR_NOENT); // reached the end? if (err == LFS_ERR_NOENT) { break; } // skip already moved? if (memcmp(info.name, "dir", strlen("dir")) != 0) { continue; } assert(i < 2*N); assert(info.type == LFS_TYPE_DIR); char old_path[1024]; sprintf(old_path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); char new_path[1024]; sprintf(new_path, "%s/%smved%s", (PARENT == 1 ? "pricklypear" : PARENT >= 2 ? "quiabentia" : ""), (BEFORE ? "0" : ""), &info.name[strlen("dir")]); err = lfsr_rename(&lfs, old_path, new_path); assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); // seek between renames? this tests that the internal position is // updated correctly if (SEEK) { lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); assert(off >= 0); if (SEEK >= 2) { lfsr_dir_rewind(&lfs, &dir) => 0; } lfsr_dir_seek(&lfs, &dir, off) => 0; } } lfsr_dir_close(&lfs, &dir) => 0; // check that our renames worked for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); struct lfs_info info; lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; sprintf(name, "%s/%smved%04d", (PARENT == 1 ? "pricklypear" : PARENT >= 2 ? "quiabentia" : ""), (BEFORE ? "0" : ""), i); lfsr_stat(&lfs, name, &info) => 0; char name2[256]; sprintf(name2, "%smved%04d", (BEFORE ? "0" : ""), i); assert(strcmp(info.name, name2) == 0); assert(info.type == LFS_TYPE_DIR); } lfsr_dir_open(&lfs, &dir, (PARENT == 1 ? "pricklypear" : PARENT >= 2 ? "quiabentia" : "/")) => 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); for (lfs_size_t i = 0; i < N; i++) { char name[256]; sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, 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_dirs_root] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_many_creation] #defines.N = 'range(3, 100, 3)' #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "dir%03d", i); # lfs_mkdir(&lfs, path) => 0; # } # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "dir%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_many_removal] #defines.N = 'range(3, 100, 11)' #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "removeme%03d", i); # lfs_mkdir(&lfs, path) => 0; # } # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "removeme%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "removeme%03d", i); # lfs_remove(&lfs, path) => 0; # } # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_many_rename] #defines.N = 'range(3, 100, 11)' #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "test%03d", i); # lfs_mkdir(&lfs, path) => 0; # } # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "test%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char oldpath[128]; # char newpath[128]; # sprintf(oldpath, "test%03d", i); # sprintf(newpath, "tedd%03d", i); # lfs_rename(&lfs, oldpath, newpath) => 0; # } # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "tedd%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); #''' # #[cases.test_dirs_many_reentrant] #defines.N = [5, 11] #if = 'BLOCK_COUNT >= 4*N' #reentrant = true #code = ''' # lfs_t lfs; # int err = lfs_mount(&lfs, cfg); # if (err) { # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # } # # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hi%03d", i); # err = lfs_mkdir(&lfs, path); # assert(err == 0 || err == LFS_ERR_EXIST); # } # # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hello%03d", i); # err = lfs_remove(&lfs, path); # assert(err == 0 || err == LFS_ERR_NOENT); # } # # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hi%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # # for (int i = 0; i < N; i++) { # char oldpath[128]; # char newpath[128]; # sprintf(oldpath, "hi%03d", i); # sprintf(newpath, "hello%03d", i); # // YES this can overwrite an existing newpath # lfs_rename(&lfs, oldpath, newpath) => 0; # } # # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hello%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hello%03d", i); # lfs_remove(&lfs, path) => 0; # } # # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_file_creation] #defines.N = 'range(3, 100, 11)' #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "file%03d", i); # lfs_file_t file; # lfs_file_open(&lfs, &file, path, # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; # lfs_file_close(&lfs, &file) => 0; # } # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "file%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); #''' # #[cases.test_dirs_file_removal] #defines.N = 'range(3, 100, 11)' #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "removeme%03d", i); # lfs_file_t file; # lfs_file_open(&lfs, &file, path, # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; # lfs_file_close(&lfs, &file) => 0; # } # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "removeme%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "removeme%03d", i); # lfs_remove(&lfs, path) => 0; # } # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_file_rename] #defines.N = 'range(3, 100, 11)' #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "test%03d", i); # lfs_file_t file; # lfs_file_open(&lfs, &file, path, # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; # lfs_file_close(&lfs, &file) => 0; # } # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "test%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < N; i++) { # char oldpath[128]; # char newpath[128]; # sprintf(oldpath, "test%03d", i); # sprintf(newpath, "tedd%03d", i); # lfs_rename(&lfs, oldpath, newpath) => 0; # } # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "tedd%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); #''' # #[cases.test_dirs_file_reentrant] #defines.N = [5, 25] #if = 'N < BLOCK_COUNT/2' #reentrant = true #code = ''' # lfs_t lfs; # int err = lfs_mount(&lfs, cfg); # if (err) { # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # } # # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hi%03d", i); # lfs_file_t file; # lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; # lfs_file_close(&lfs, &file) => 0; # } # # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hello%03d", i); # err = lfs_remove(&lfs, path); # assert(err == 0 || err == LFS_ERR_NOENT); # } # # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hi%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # # for (int i = 0; i < N; i++) { # char oldpath[128]; # char newpath[128]; # sprintf(oldpath, "hi%03d", i); # sprintf(newpath, "hello%03d", i); # // YES this can overwrite an existing newpath # lfs_rename(&lfs, oldpath, newpath) => 0; # } # # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hello%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "hello%03d", i); # lfs_remove(&lfs, path) => 0; # } # # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_nested] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "potato") => 0; # lfs_file_t file; # lfs_file_open(&lfs, &file, "burito", # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; # lfs_file_close(&lfs, &file) => 0; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "potato/baked") => 0; # lfs_mkdir(&lfs, "potato/sweet") => 0; # lfs_mkdir(&lfs, "potato/fried") => 0; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "potato") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "baked") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "fried") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "sweet") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; # # // try removing? # lfs_mount(&lfs, cfg) => 0; # lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; # lfs_unmount(&lfs) => 0; # # // try renaming? # lfs_mount(&lfs, cfg) => 0; # lfs_rename(&lfs, "potato", "coldpotato") => 0; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; # lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; # lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; # lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_unmount(&lfs) => 0; # # // try cross-directory renaming # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "coldpotato") => 0; # lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; # lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_rename(&lfs, "hotpotato/fried", "coldpotato/fried") => 0; # lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_rename(&lfs, "hotpotato/sweet", "coldpotato/sweet") => 0; # lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; # lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "hotpotato") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "baked") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "fried") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "sweet") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; # # // final remove # lfs_mount(&lfs, cfg) => 0; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "hotpotato/baked") => 0; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "hotpotato/fried") => 0; # lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; # lfs_remove(&lfs, "hotpotato/sweet") => 0; # lfs_remove(&lfs, "hotpotato") => 0; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # info.type => LFS_TYPE_DIR; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "burito") == 0); # info.type => LFS_TYPE_REG; # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_recursive_remove] #defines.N = [10, 100] #if = 'N < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "prickly-pear") => 0; # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "prickly-pear/cactus%03d", i); # lfs_mkdir(&lfs, path) => 0; # } # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "cactus%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs); # # lfs_mount(&lfs, cfg) => 0; # lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; # # lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # for (int i = 0; i < N; i++) { # char path[1024]; # sprintf(path, "cactus%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, path) == 0); # sprintf(path, "prickly-pear/%s", info.name); # lfs_remove(&lfs, path) => 0; # } # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # # lfs_remove(&lfs, "prickly-pear") => 0; # lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_other_errors] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "potato") => 0; # lfs_file_t file; # lfs_file_open(&lfs, &file, "burito", # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; # lfs_file_close(&lfs, &file) => 0; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # # lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; # lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; # lfs_file_open(&lfs, &file, "burito", # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; # lfs_file_open(&lfs, &file, "potato", # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT; # lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR; # lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; # lfs_file_open(&lfs, &file, "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; # lfs_file_open(&lfs, &file, "tomato", LFS_O_WRONLY) => LFS_ERR_NOENT; # lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY) => LFS_ERR_ISDIR; # lfs_file_open(&lfs, &file, "potato", # LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; # # lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; # lfs_file_open(&lfs, &file, "/", # LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; # lfs_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_ISDIR; # lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_ISDIR; # lfs_file_open(&lfs, &file, "/", # LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; # # // check that errors did not corrupt directory # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, "burito") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "potato") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # # lfs_unmount(&lfs) => 0; # # // or on disk # lfs_mount(&lfs, cfg) => 0; # lfs_dir_open(&lfs, &dir, "/") => 0; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, ".") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "..") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_REG); # assert(strcmp(info.name, "burito") == 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(info.type == LFS_TYPE_DIR); # assert(strcmp(info.name, "potato") == 0); # lfs_dir_read(&lfs, &dir, &info) => 0; # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; #''' # #[cases.test_dirs_seek] #defines.COUNT = [4, 128, 132] #if = 'COUNT < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "hello") => 0; # for (int i = 0; i < COUNT; i++) { # char path[1024]; # sprintf(path, "hello/kitty%03d", i); # lfs_mkdir(&lfs, path) => 0; # } # lfs_unmount(&lfs) => 0; # # for (int j = 2; j < COUNT; j++) { # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "hello") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # assert(info.type == LFS_TYPE_DIR); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_soff_t pos; # for (int i = 0; i < j; i++) { # char path[1024]; # sprintf(path, "kitty%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # pos = lfs_dir_tell(&lfs, &dir); # assert(pos >= 0); # } # # lfs_dir_seek(&lfs, &dir, pos) => 0; # char path[1024]; # sprintf(path, "kitty%03d", j); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_dir_rewind(&lfs, &dir) => 0; # sprintf(path, "kitty%03u", 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # assert(info.type == LFS_TYPE_DIR); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # assert(info.type == LFS_TYPE_DIR); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_dir_seek(&lfs, &dir, pos) => 0; # sprintf(path, "kitty%03d", j); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; # } #''' # #[cases.test_dirs_toot_seek] #defines.COUNT = [4, 128, 132] #if = 'COUNT < BLOCK_COUNT/2' #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # for (int i = 0; i < COUNT; i++) { # char path[1024]; # sprintf(path, "hi%03d", i); # lfs_mkdir(&lfs, path) => 0; # } # lfs_unmount(&lfs) => 0; # # for (int j = 2; j < COUNT; j++) { # lfs_mount(&lfs, cfg) => 0; # lfs_dir_t dir; # lfs_dir_open(&lfs, &dir, "/") => 0; # struct lfs_info info; # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # assert(info.type == LFS_TYPE_DIR); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_soff_t pos; # for (int i = 0; i < j; i++) { # char path[1024]; # sprintf(path, "hi%03d", i); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # pos = lfs_dir_tell(&lfs, &dir); # assert(pos >= 0); # } # # lfs_dir_seek(&lfs, &dir, pos) => 0; # char path[1024]; # sprintf(path, "hi%03d", j); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_dir_rewind(&lfs, &dir) => 0; # sprintf(path, "hi%03u", 0); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, ".") == 0); # assert(info.type == LFS_TYPE_DIR); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, "..") == 0); # assert(info.type == LFS_TYPE_DIR); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_dir_seek(&lfs, &dir, pos) => 0; # sprintf(path, "hi%03d", j); # lfs_dir_read(&lfs, &dir, &info) => 1; # assert(strcmp(info.name, path) == 0); # assert(info.type == LFS_TYPE_DIR); # # lfs_dir_close(&lfs, &dir) => 0; # lfs_unmount(&lfs) => 0; # } #''' #