/* * Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2023 Antmicro * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include "test_fs_util.h" /* Mount point for the tests should be provided by test runner. * File system should be mounted before tests are started. */ extern struct fs_mount_t *fs_dirops_test_mp; static struct testfs_bcmd test_hierarchy[] = { TESTFS_BCMD_FILE("f1", 1, 1), TESTFS_BCMD_FILE("f2", 2, 100), TESTFS_BCMD_ENTER_DIR("d1"), TESTFS_BCMD_FILE("d1f1", 11, 23), TESTFS_BCMD_FILE("d1f2", 12, 612), TESTFS_BCMD_EXIT_DIR(), TESTFS_BCMD_FILE("f3", 3, 10000), TESTFS_BCMD_END(), }; static int check_mkdir(struct fs_mount_t *mp) { struct testfs_path dpath; TC_PRINT("checking dir create unlink\n"); zassert_equal(testfs_path_init(&dpath, mp, "dir", TESTFS_PATH_END), dpath.path, "root init failed"); zassert_equal(fs_mkdir(dpath.path), 0, "mkdir failed"); struct fs_file_t file; struct testfs_path fpath; fs_file_t_init(&file); zassert_equal(fs_open(&file, testfs_path_extend(testfs_path_copy(&fpath, &dpath), "file", TESTFS_PATH_END), FS_O_CREATE | FS_O_RDWR), 0, "creat in dir failed"); zassert_equal(fs_close(&file), 0, "close file failed"); struct fs_dirent stat; zassert_equal(fs_stat(fpath.path, &stat), 0, "stat file failed"); zassert_equal(fs_unlink(dpath.path), -ENOTEMPTY, "unlink bad failure"); zassert_equal(fs_unlink(fpath.path), 0, "unlink file failed"); zassert_equal(fs_unlink(dpath.path), 0, "unlink dir failed"); return TC_PASS; } static int build_layout(struct fs_mount_t *mp, const struct testfs_bcmd *cp) { struct testfs_path path; struct fs_statvfs stat; TC_PRINT("building layout on %s\n", mp->mnt_point); zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0, "statvfs failed"); TC_PRINT("before: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n", stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree); zassert_equal(testfs_path_init(&path, mp, TESTFS_PATH_END), path.path, "root init failed"); zassert_equal(testfs_build(&path, cp), 0, "Build_layout failed"); zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0, "statvfs failed"); TC_PRINT("after: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n", stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree); return TC_PASS; } static int check_layout(struct fs_mount_t *mp, struct testfs_bcmd *layout) { struct testfs_path path; struct testfs_bcmd *end_layout = testfs_bcmd_end(layout); TC_PRINT("checking layout\n"); zassert_equal(testfs_path_init(&path, mp, TESTFS_PATH_END), path.path, "root init failed"); int rc = testfs_bcmd_verify_layout(&path, layout, end_layout); zassert_true(rc >= 0, "layout check failed"); zassert_equal(rc, 0, "layout found foreign"); struct testfs_bcmd *cp = layout; while (!TESTFS_BCMD_IS_END(cp)) { if (cp->name != NULL) { TC_PRINT("verifying %s%s %u\n", cp->name, (cp->type == FS_DIR_ENTRY_DIR) ? "/" : "", cp->size); zassert_true(cp->matched, "Unmatched layout entry"); } ++cp; } return TC_PASS; } static int check_rename(struct fs_mount_t *mp) { struct testfs_path root; struct testfs_path from_path; const char *from = from_path.path; struct testfs_path to_path; const char *to = to_path.path; struct fs_dirent stat; struct testfs_bcmd from_bcmd[] = { TESTFS_BCMD_FILE("f1f", 1, 8), /* from f1f to f1t */ TESTFS_BCMD_FILE("f2f", 2, 8), /* from f2f to f2t */ TESTFS_BCMD_FILE("f2t", 3, 8), /* target for f2f clobber, replaced */ TESTFS_BCMD_FILE("f3f", 4, 8), /* from f3f to d1f/d1f2t */ TESTFS_BCMD_FILE("f4f", 5, 8), /* from f4f to d2t, reject */ TESTFS_BCMD_ENTER_DIR("d1f"), /* from d1f to d1t */ TESTFS_BCMD_FILE("d1f1", 5, 16), TESTFS_BCMD_EXIT_DIR(), TESTFS_BCMD_ENTER_DIR("d2t"), /* target for d1f, unchanged */ TESTFS_BCMD_FILE("d2f1", 6, 16), TESTFS_BCMD_EXIT_DIR(), TESTFS_BCMD_END(), }; struct testfs_bcmd *from_end_bcmd = testfs_bcmd_end(from_bcmd); struct testfs_bcmd to_bcmd[] = { TESTFS_BCMD_FILE("f1t", 1, 8), /* from f1f to f1t */ TESTFS_BCMD_FILE("f2t", 2, 8), /* from f2f to f2t */ TESTFS_BCMD_FILE("f4f", 5, 8), /* from f4f to d2t, reject */ TESTFS_BCMD_ENTER_DIR("d1t"), /* from d1f to d1t */ TESTFS_BCMD_FILE("d1f1", 5, 16), TESTFS_BCMD_FILE("d1f2t", 4, 8), /* from f3f to d1f/d1f2t */ TESTFS_BCMD_EXIT_DIR(), TESTFS_BCMD_ENTER_DIR("d2t"), /* target for d1f, unchanged */ TESTFS_BCMD_FILE("d2f1", 6, 16), TESTFS_BCMD_EXIT_DIR(), TESTFS_BCMD_END(), }; struct testfs_bcmd *to_end_bcmd = testfs_bcmd_end(to_bcmd); zassert_equal(testfs_path_init(&root, mp, "rename", TESTFS_PATH_END), root.path, "root init failed"); zassert_equal(fs_mkdir(root.path), 0, "rename mkdir failed"); zassert_equal(testfs_build(&root, from_bcmd), 0, "rename build failed"); zassert_equal(testfs_bcmd_verify_layout(&root, from_bcmd, from_end_bcmd), 0, "layout check failed"); testfs_path_extend(testfs_path_copy(&from_path, &root), "nofile", TESTFS_PATH_END); testfs_path_extend(testfs_path_copy(&to_path, &root), "f1t", TESTFS_PATH_END); TC_PRINT("%s => %s -ENOENT\n", from, to); zassert_equal(fs_rename(from, to), -ENOENT, "rename noent failed"); /* f1f => f1t : ok */ testfs_path_extend(testfs_path_copy(&from_path, &root), "f1f", TESTFS_PATH_END); TC_PRINT("%s => %s ok\n", from, to); zassert_equal(fs_rename(from, to), 0, "rename noent failed"); /* f2f => f2t : clobbers */ testfs_path_extend(testfs_path_copy(&from_path, &root), "f2f", TESTFS_PATH_END); testfs_path_extend(testfs_path_copy(&to_path, &root), "f2t", TESTFS_PATH_END); TC_PRINT("%s => %s clobber ok\n", from, to); zassert_equal(fs_rename(from, to), 0, "rename clobber failed"); zassert_equal(fs_stat(from, &stat), -ENOENT, "rename clobber left from"); /* f3f => d1f/d1f2t : moves */ testfs_path_extend(testfs_path_copy(&from_path, &root), "f3f", TESTFS_PATH_END); testfs_path_extend(testfs_path_copy(&to_path, &root), "d1f", "d1f2t", TESTFS_PATH_END); TC_PRINT("%s => %s move ok\n", from, to); zassert_equal(fs_rename(from, to), 0, "rename to subdir failed"); zassert_equal(fs_stat(from, &stat), -ENOENT, "rename to subdir left from"); /* d1f => d2t : reject */ testfs_path_extend(testfs_path_copy(&from_path, &root), "d1f", TESTFS_PATH_END); testfs_path_extend(testfs_path_copy(&to_path, &root), "d2t", TESTFS_PATH_END); TC_PRINT("%s => %s -ENOTEMPTY\n", from, to); zassert_equal(fs_rename(from, to), -ENOTEMPTY, "rename to existing dir failed"); /* d1f => d1t : rename */ testfs_path_extend(testfs_path_copy(&from_path, &root), "d1f", TESTFS_PATH_END); testfs_path_extend(testfs_path_copy(&to_path, &root), "d1t", TESTFS_PATH_END); TC_PRINT("%s => %s ok\n", from, to); zassert_equal(fs_rename(from, to), 0, "rename to new dir failed"); zassert_equal(fs_stat(from, &stat), -ENOENT, "rename to new dir left from"); zassert_equal(testfs_bcmd_verify_layout(&root, to_bcmd, to_end_bcmd), 0, "layout verification failed"); struct testfs_bcmd *cp = to_bcmd; while (cp != to_end_bcmd) { if (cp->name) { zassert_true(cp->matched, "foreign file retained"); } ++cp; } return TC_PASS; } void test_fs_dirops(void) { zassert_equal(fs_mount(fs_dirops_test_mp), 0, "mount failed"); zassert_equal(check_mkdir(fs_dirops_test_mp), TC_PASS, "check mkdir failed"); k_sleep(K_MSEC(100)); /* flush log messages */ zassert_equal(build_layout(fs_dirops_test_mp, test_hierarchy), TC_PASS, "build test hierarchy failed"); k_sleep(K_MSEC(100)); /* flush log messages */ zassert_equal(check_layout(fs_dirops_test_mp, test_hierarchy), TC_PASS, "check test hierarchy failed"); k_sleep(K_MSEC(100)); /* flush log messages */ zassert_equal(check_rename(fs_dirops_test_mp), TC_PASS, "check rename failed"); k_sleep(K_MSEC(100)); /* flush log messages */ zassert_equal(fs_unmount(fs_dirops_test_mp), 0, "unmount small failed"); }