blob: 5b564ddebb88ca875253b22fa1a69b1f42ffd7b8 [file] [log] [blame]
/*
* Copyright (c) 2019 Peter Bigot Consulting, LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Director littlefs operations:
* * mkdir
* * opendir
* * readdir
* * closedir
* * rename
*/
#include <string.h>
#include <zephyr/ztest.h>
#include "testfs_tests.h"
#include "testfs_lfs.h"
#include <lfs.h>
#include <zephyr/fs/littlefs.h>
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 clean_mount(struct fs_mount_t *mp)
{
TC_PRINT("checking clean mount\n");
zassert_equal(testfs_lfs_wipe_partition(mp),
TC_PASS,
"failed to wipe partition");
zassert_equal(fs_mount(mp), 0,
"mount small failed");
return TC_PASS;
}
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_lfs_dirops(void)
{
struct fs_mount_t *mp = &testfs_small_mnt;
zassert_equal(clean_mount(mp), TC_PASS,
"clean mount failed");
zassert_equal(check_mkdir(mp), TC_PASS,
"check mkdir failed");
k_sleep(K_MSEC(100)); /* flush log messages */
zassert_equal(build_layout(mp, test_hierarchy), TC_PASS,
"build test hierarchy failed");
k_sleep(K_MSEC(100)); /* flush log messages */
zassert_equal(check_layout(mp, test_hierarchy), TC_PASS,
"check test hierarchy failed");
k_sleep(K_MSEC(100)); /* flush log messages */
zassert_equal(check_rename(mp), TC_PASS,
"check rename failed");
k_sleep(K_MSEC(100)); /* flush log messages */
zassert_equal(fs_unmount(mp), 0,
"unmount small failed");
}