1 /*
2 * Copyright (c) 2019 Peter Bigot Consulting, LLC
3 * Copyright (c) 2023 Antmicro
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/fs/fs.h>
10
11 #include "test_fs_util.h"
12
13 /* Mount point for the tests should be provided by test runner.
14 * File system should be mounted before tests are started.
15 */
16 extern struct fs_mount_t *fs_dirops_test_mp;
17
18 static struct testfs_bcmd test_hierarchy[] = {
19 TESTFS_BCMD_FILE("f1", 1, 1),
20 TESTFS_BCMD_FILE("f2", 2, 100),
21 TESTFS_BCMD_ENTER_DIR("d1"),
22 TESTFS_BCMD_FILE("d1f1", 11, 23),
23 TESTFS_BCMD_FILE("d1f2", 12, 612),
24 TESTFS_BCMD_EXIT_DIR(),
25 TESTFS_BCMD_FILE("f3", 3, 10000),
26 TESTFS_BCMD_END(),
27 };
28
check_mkdir(struct fs_mount_t * mp)29 static int check_mkdir(struct fs_mount_t *mp)
30 {
31 struct testfs_path dpath;
32
33 TC_PRINT("checking dir create unlink\n");
34 zassert_equal(testfs_path_init(&dpath, mp,
35 "dir",
36 TESTFS_PATH_END),
37 dpath.path,
38 "root init failed");
39
40 zassert_equal(fs_mkdir(dpath.path),
41 0,
42 "mkdir failed");
43
44 struct fs_file_t file;
45 struct testfs_path fpath;
46
47 fs_file_t_init(&file);
48 zassert_equal(fs_open(&file,
49 testfs_path_extend(testfs_path_copy(&fpath,
50 &dpath),
51 "file",
52 TESTFS_PATH_END),
53 FS_O_CREATE | FS_O_RDWR),
54 0,
55 "creat in dir failed");
56 zassert_equal(fs_close(&file), 0,
57 "close file failed");
58
59 struct fs_dirent stat;
60
61 zassert_equal(fs_stat(fpath.path, &stat), 0,
62 "stat file failed");
63
64 zassert_equal(fs_unlink(dpath.path),
65 -ENOTEMPTY,
66 "unlink bad failure");
67
68 zassert_equal(fs_unlink(fpath.path),
69 0,
70 "unlink file failed");
71
72 zassert_equal(fs_unlink(dpath.path),
73 0,
74 "unlink dir failed");
75
76 return TC_PASS;
77 }
78
build_layout(struct fs_mount_t * mp,const struct testfs_bcmd * cp)79 static int build_layout(struct fs_mount_t *mp,
80 const struct testfs_bcmd *cp)
81 {
82 struct testfs_path path;
83 struct fs_statvfs stat;
84
85 TC_PRINT("building layout on %s\n", mp->mnt_point);
86
87 zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
88 "statvfs failed");
89
90 TC_PRINT("before: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
91 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
92
93 zassert_equal(testfs_path_init(&path, mp, TESTFS_PATH_END),
94 path.path,
95 "root init failed");
96
97 zassert_equal(testfs_build(&path, cp),
98 0,
99 "Build_layout failed");
100
101 zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
102 "statvfs failed");
103
104 TC_PRINT("after: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
105 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
106
107 return TC_PASS;
108 }
109
check_layout(struct fs_mount_t * mp,struct testfs_bcmd * layout)110 static int check_layout(struct fs_mount_t *mp,
111 struct testfs_bcmd *layout)
112 {
113 struct testfs_path path;
114 struct testfs_bcmd *end_layout = testfs_bcmd_end(layout);
115
116 TC_PRINT("checking layout\n");
117
118 zassert_equal(testfs_path_init(&path, mp, TESTFS_PATH_END),
119 path.path,
120 "root init failed");
121
122 int rc = testfs_bcmd_verify_layout(&path, layout, end_layout);
123
124 zassert_true(rc >= 0, "layout check failed");
125
126 zassert_equal(rc, 0,
127 "layout found foreign");
128
129 struct testfs_bcmd *cp = layout;
130
131 while (!TESTFS_BCMD_IS_END(cp)) {
132 if (cp->name != NULL) {
133 TC_PRINT("verifying %s%s %u\n",
134 cp->name,
135 (cp->type == FS_DIR_ENTRY_DIR) ? "/" : "",
136 cp->size);
137 zassert_true(cp->matched,
138 "Unmatched layout entry");
139 }
140 ++cp;
141 }
142
143 return TC_PASS;
144 }
145
check_rename(struct fs_mount_t * mp)146 static int check_rename(struct fs_mount_t *mp)
147 {
148 struct testfs_path root;
149 struct testfs_path from_path;
150 const char *from = from_path.path;
151 struct testfs_path to_path;
152 const char *to = to_path.path;
153 struct fs_dirent stat;
154 struct testfs_bcmd from_bcmd[] = {
155 TESTFS_BCMD_FILE("f1f", 1, 8), /* from f1f to f1t */
156 TESTFS_BCMD_FILE("f2f", 2, 8), /* from f2f to f2t */
157 TESTFS_BCMD_FILE("f2t", 3, 8), /* target for f2f clobber, replaced */
158 TESTFS_BCMD_FILE("f3f", 4, 8), /* from f3f to d1f/d1f2t */
159 TESTFS_BCMD_FILE("f4f", 5, 8), /* from f4f to d2t, reject */
160 TESTFS_BCMD_ENTER_DIR("d1f"), /* from d1f to d1t */
161 TESTFS_BCMD_FILE("d1f1", 5, 16),
162 TESTFS_BCMD_EXIT_DIR(),
163 TESTFS_BCMD_ENTER_DIR("d2t"), /* target for d1f, unchanged */
164 TESTFS_BCMD_FILE("d2f1", 6, 16),
165 TESTFS_BCMD_EXIT_DIR(),
166 TESTFS_BCMD_END(),
167 };
168 struct testfs_bcmd *from_end_bcmd = testfs_bcmd_end(from_bcmd);
169 struct testfs_bcmd to_bcmd[] = {
170 TESTFS_BCMD_FILE("f1t", 1, 8), /* from f1f to f1t */
171 TESTFS_BCMD_FILE("f2t", 2, 8), /* from f2f to f2t */
172 TESTFS_BCMD_FILE("f4f", 5, 8), /* from f4f to d2t, reject */
173 TESTFS_BCMD_ENTER_DIR("d1t"), /* from d1f to d1t */
174 TESTFS_BCMD_FILE("d1f1", 5, 16),
175 TESTFS_BCMD_FILE("d1f2t", 4, 8), /* from f3f to d1f/d1f2t */
176 TESTFS_BCMD_EXIT_DIR(),
177 TESTFS_BCMD_ENTER_DIR("d2t"), /* target for d1f, unchanged */
178 TESTFS_BCMD_FILE("d2f1", 6, 16),
179 TESTFS_BCMD_EXIT_DIR(),
180 TESTFS_BCMD_END(),
181 };
182 struct testfs_bcmd *to_end_bcmd = testfs_bcmd_end(to_bcmd);
183
184 zassert_equal(testfs_path_init(&root, mp,
185 "rename",
186 TESTFS_PATH_END),
187 root.path,
188 "root init failed");
189
190 zassert_equal(fs_mkdir(root.path),
191 0,
192 "rename mkdir failed");
193 zassert_equal(testfs_build(&root, from_bcmd),
194 0,
195 "rename build failed");
196
197 zassert_equal(testfs_bcmd_verify_layout(&root, from_bcmd, from_end_bcmd),
198 0,
199 "layout check failed");
200
201 testfs_path_extend(testfs_path_copy(&from_path, &root),
202 "nofile",
203 TESTFS_PATH_END);
204 testfs_path_extend(testfs_path_copy(&to_path, &root),
205 "f1t",
206 TESTFS_PATH_END);
207 TC_PRINT("%s => %s -ENOENT\n", from, to);
208 zassert_equal(fs_rename(from, to),
209 -ENOENT,
210 "rename noent failed");
211
212 /* f1f => f1t : ok */
213 testfs_path_extend(testfs_path_copy(&from_path, &root),
214 "f1f",
215 TESTFS_PATH_END);
216 TC_PRINT("%s => %s ok\n", from, to);
217 zassert_equal(fs_rename(from, to),
218 0,
219 "rename noent failed");
220
221 /* f2f => f2t : clobbers */
222 testfs_path_extend(testfs_path_copy(&from_path, &root),
223 "f2f",
224 TESTFS_PATH_END);
225 testfs_path_extend(testfs_path_copy(&to_path, &root),
226 "f2t",
227 TESTFS_PATH_END);
228 TC_PRINT("%s => %s clobber ok\n", from, to);
229 zassert_equal(fs_rename(from, to),
230 0,
231 "rename clobber failed");
232 zassert_equal(fs_stat(from, &stat),
233 -ENOENT,
234 "rename clobber left from");
235
236 /* f3f => d1f/d1f2t : moves */
237 testfs_path_extend(testfs_path_copy(&from_path, &root),
238 "f3f",
239 TESTFS_PATH_END);
240 testfs_path_extend(testfs_path_copy(&to_path, &root),
241 "d1f", "d1f2t",
242 TESTFS_PATH_END);
243 TC_PRINT("%s => %s move ok\n", from, to);
244 zassert_equal(fs_rename(from, to),
245 0,
246 "rename to subdir failed");
247 zassert_equal(fs_stat(from, &stat),
248 -ENOENT,
249 "rename to subdir left from");
250
251 /* d1f => d2t : reject */
252 testfs_path_extend(testfs_path_copy(&from_path, &root),
253 "d1f",
254 TESTFS_PATH_END);
255 testfs_path_extend(testfs_path_copy(&to_path, &root),
256 "d2t",
257 TESTFS_PATH_END);
258 TC_PRINT("%s => %s -ENOTEMPTY\n", from, to);
259 zassert_equal(fs_rename(from, to),
260 -ENOTEMPTY,
261 "rename to existing dir failed");
262
263 /* d1f => d1t : rename */
264 testfs_path_extend(testfs_path_copy(&from_path, &root),
265 "d1f",
266 TESTFS_PATH_END);
267 testfs_path_extend(testfs_path_copy(&to_path, &root),
268 "d1t",
269 TESTFS_PATH_END);
270 TC_PRINT("%s => %s ok\n", from, to);
271 zassert_equal(fs_rename(from, to),
272 0,
273 "rename to new dir failed");
274 zassert_equal(fs_stat(from, &stat),
275 -ENOENT,
276 "rename to new dir left from");
277
278 zassert_equal(testfs_bcmd_verify_layout(&root, to_bcmd, to_end_bcmd),
279 0,
280 "layout verification failed");
281
282 struct testfs_bcmd *cp = to_bcmd;
283
284 while (cp != to_end_bcmd) {
285 if (cp->name) {
286 zassert_true(cp->matched, "foreign file retained");
287 }
288 ++cp;
289 }
290
291 return TC_PASS;
292 }
293
test_fs_dirops(void)294 void test_fs_dirops(void)
295 {
296 zassert_equal(fs_mount(fs_dirops_test_mp), 0,
297 "mount failed");
298
299 zassert_equal(check_mkdir(fs_dirops_test_mp), TC_PASS,
300 "check mkdir failed");
301
302 k_sleep(K_MSEC(100)); /* flush log messages */
303 zassert_equal(build_layout(fs_dirops_test_mp, test_hierarchy), TC_PASS,
304 "build test hierarchy failed");
305
306 k_sleep(K_MSEC(100)); /* flush log messages */
307 zassert_equal(check_layout(fs_dirops_test_mp, test_hierarchy), TC_PASS,
308 "check test hierarchy failed");
309
310 k_sleep(K_MSEC(100)); /* flush log messages */
311 zassert_equal(check_rename(fs_dirops_test_mp), TC_PASS,
312 "check rename failed");
313
314 k_sleep(K_MSEC(100)); /* flush log messages */
315 zassert_equal(fs_unmount(fs_dirops_test_mp), 0,
316 "unmount small failed");
317 }
318