1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @filesystem
9 * @brief test_filesystem
10 * Tests the fs_open flags
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/ztest.h>
15 #include <zephyr/fs/fs.h>
16 #include <string.h>
17
18 /* Path for testr file should be provided by test runner and should start
19 * with mount point.
20 */
21 extern char *test_fs_open_flags_file_path;
22
23 static const char something[] = "Something";
24 static char buffer[sizeof(something)];
25 #define RDWR_SIZE sizeof(something)
26
27 struct test_state {
28 /* Path to file */
29 char *file_path;
30 struct fs_file_t file;
31 /* Read write buffer info */
32 const char *write;
33 int write_size;
34 char *read;
35 int read_size;
36 };
37
38 /* ZEQ decides whether test completed successfully and prints appropriate
39 * information.
40 */
ZEQ(int ret,int expected)41 static void ZEQ(int ret, int expected)
42 {
43 zassert_equal(ret, expected,
44 "FAILED: expected = %d, ret = %d, errno = %d\n",
45 expected, ret, errno);
46 TC_PRINT("SUCCESS\n");
47 }
48
49 /* NOTE: Below functions have C preprocessor redefinitions that automatically
50 * fill in the line parameter, so when invoking, do not provide the line
51 * parameter.
52 */
53
54 /* Test fs_open, expected is the return value expected from fs_open */
ZOPEN(struct test_state * ts,int flags,int expected,int line)55 static void ZOPEN(struct test_state *ts, int flags, int expected, int line)
56 {
57 TC_PRINT("# %d: OPEN %s with flags %x\n", line, ts->file_path, flags);
58 ZEQ(fs_open(&ts->file, ts->file_path, flags), expected);
59 }
60
61 /* Close file. Will automatically fail test case if unsuccessful. */
ZCLOSE(struct test_state * ts,int line)62 static void ZCLOSE(struct test_state *ts, int line)
63 {
64 TC_PRINT("# %d: CLOSE %s\n", line, ts->file_path);
65 ZEQ(fs_close(&ts->file), 0);
66 }
67
68 /* Attempt to write to file; expected is what fs_write is supposed to return */
ZWRITE(struct test_state * ts,int expected,int line)69 static void ZWRITE(struct test_state *ts, int expected, int line)
70 {
71 TC_PRINT("# %d: WRITE %s\n", line, ts->file_path);
72 ZEQ(fs_write(&ts->file, ts->write, ts->write_size), expected);
73 }
74
75 /* Attempt to read from file; expected is what fs_read is supposed to return */
ZREAD(struct test_state * ts,int expected,int line)76 static void ZREAD(struct test_state *ts, int expected, int line)
77 {
78 TC_PRINT("# %d: READ %s\n", line, ts->file_path);
79 ZEQ(fs_read(&ts->file, ts->read, ts->read_size), expected);
80 }
81
82 /* Unlink/delete file. Will automatically fail test case if unsuccessful. */
ZUNLINK(struct test_state * ts,int line)83 static void ZUNLINK(struct test_state *ts, int line)
84 {
85 int ret;
86
87 TC_PRINT("# %d: UNLINK %s\n", line, ts->file_path);
88 ret = fs_unlink(ts->file_path);
89 zassert((ret == 0 || ret == -ENOENT), "Done", "Failed");
90 TC_PRINT("SUCCESS\n");
91 }
92
93 /* Check file position; expected is a position file should be at. */
ZCHKPOS(struct test_state * ts,off_t expected,int line)94 static void ZCHKPOS(struct test_state *ts, off_t expected, int line)
95 {
96 TC_PRINT("# %d: CHKPOS\n", line);
97 ZEQ(fs_tell(&ts->file), expected);
98 }
99
100 /* Rewind file. */
ZREWIND(struct test_state * ts,int line)101 static void ZREWIND(struct test_state *ts, int line)
102 {
103 TC_PRINT("# %d: REWIND\n", line);
104 ZEQ(fs_seek(&ts->file, 0, FS_SEEK_SET), 0);
105 }
106
107 /* Banner definitions, print BEGIN/END banner with block number.
108 * Require definition of block variable with vale that will represent first
109 * test block number; the variable is automatically incremented by END.
110 */
111 #define ZBEGIN(info) \
112 TC_PRINT("\n## BEGIN %d: %s (line %d)\n", block, info, __LINE__)
113 #define ZEND() TC_PRINT("## END %d\n", block++)
114
115 /* C preprocessor redefinitions that automatically fill in line parameter */
116 #define ZOPEN(ts, flags, expected) ZOPEN(ts, flags, expected, __LINE__)
117 #define ZCLOSE(ts) ZCLOSE(ts, __LINE__)
118 #define ZWRITE(ts, expected) ZWRITE(ts, expected, __LINE__)
119 #define ZREAD(ts, expected) ZREAD(ts, expected, __LINE__)
120 #define ZUNLINK(ts) ZUNLINK(ts, __LINE__)
121 #define ZCHKPOS(ts, expected) ZCHKPOS(ts, expected, __LINE__)
122 #define ZREWIND(ts) ZREWIND(ts, __LINE__)
123
124 /* Create empty file */
125 #define ZMKEMPTY(ts) \
126 do { \
127 ZUNLINK(ts); \
128 ZOPEN(ts, FS_O_CREATE, 0); \
129 ZCLOSE(ts); \
130 } while (0)
131
test_fs_open_flags(void)132 void test_fs_open_flags(void)
133 {
134 struct test_state ts = {
135 *&test_fs_open_flags_file_path,
136 { 0 },
137 something,
138 RDWR_SIZE,
139 buffer,
140 RDWR_SIZE,
141 };
142 int block = 1;
143
144 fs_file_t_init(&ts.file);
145
146 ZBEGIN("Attempt open non-existent");
147 ZOPEN(&ts, 0, -ENOENT);
148 ZOPEN(&ts, FS_O_WRITE, -ENOENT);
149 ZOPEN(&ts, FS_O_READ, -ENOENT);
150 ZOPEN(&ts, FS_O_RDWR, -ENOENT);
151 ZOPEN(&ts, FS_O_APPEND, -ENOENT);
152 ZOPEN(&ts, FS_O_TRUNC, -EACCES);
153 ZOPEN(&ts, FS_O_APPEND | FS_O_READ, -ENOENT);
154 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, -ENOENT);
155 ZOPEN(&ts, FS_O_APPEND | FS_O_RDWR, -ENOENT);
156 ZOPEN(&ts, FS_O_TRUNC | FS_O_RDWR, -ENOENT);
157 ZOPEN(&ts, FS_O_TRUNC | FS_O_APPEND, -EACCES);
158 ZOPEN(&ts, FS_O_TRUNC | FS_O_RDWR | FS_O_APPEND, -ENOENT);
159 ZEND();
160
161
162 /* Attempt create new file with no read/write access and check
163 * operations on it.
164 */
165 ZBEGIN("Attempt create new with no R/W access");
166 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
167 ZOPEN(&ts, FS_O_CREATE | 0, 0);
168 ZWRITE(&ts, -EACCES);
169 ZREAD(&ts, -EACCES);
170 ZCLOSE(&ts);
171 ZUNLINK(&ts);
172 #else
173 TC_PRINT("Bypassed test\n");
174 #endif
175 ZEND();
176
177
178 ZBEGIN("Attempt create new with READ access");
179 ZOPEN(&ts, FS_O_CREATE | FS_O_READ, 0);
180 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
181 ZWRITE(&ts, -EACCES);
182 #else
183 TC_PRINT("Write bypassed\n");
184 #endif
185 ZREAD(&ts, 0);
186 ZCLOSE(&ts);
187 ZUNLINK(&ts);
188 ZEND();
189
190
191 ZBEGIN("Attempt create new with WRITE access");
192 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
193 ZWRITE(&ts, ts.write_size);
194 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
195 ZREAD(&ts, -EACCES);
196 #else
197 TC_PRINT("Read bypassed\n");
198 #endif
199 ZCLOSE(&ts);
200 ZUNLINK(&ts);
201 ZEND();
202
203
204 ZBEGIN("Attempt create new with R/W access");
205 ZOPEN(&ts, FS_O_CREATE | FS_O_RDWR, 0);
206 ZWRITE(&ts, ts.write_size);
207 /* Read is done at the end of file, so 0 bytes will be read */
208 ZREAD(&ts, 0);
209 ZCLOSE(&ts);
210 ZUNLINK(&ts);
211 ZEND();
212
213
214 ZBEGIN("Attempt open existing with no R/W access");
215 ZMKEMPTY(&ts);
216 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_RW_IS_DEFAULT
217 ZOPEN(&ts, 0, 0);
218 ZWRITE(&ts, -EACCES);
219 ZREAD(&ts, -EACCES);
220 ZCLOSE(&ts);
221 #else
222 TC_PRINT("Bypassed test\n");
223 #endif
224 ZUNLINK(&ts);
225 ZEND();
226
227
228 ZBEGIN("Attempt open existing with READ access");
229 ZMKEMPTY(&ts);
230 ZOPEN(&ts, FS_O_READ, 0);
231 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
232 ZWRITE(&ts, -EACCES);
233 #else
234 TC_PRINT("Write bypassed\n");
235 #endif
236 /* File is empty */
237 ZREAD(&ts, 0);
238 ZCLOSE(&ts);
239 ZUNLINK(&ts);
240 ZEND();
241
242
243 ZBEGIN("Attempt open existing with WRITE access");
244 ZMKEMPTY(&ts);
245 ZOPEN(&ts, FS_O_WRITE, 0);
246 ZCHKPOS(&ts, 0);
247 ZWRITE(&ts, ts.write_size);
248 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
249 ZREAD(&ts, -EACCES);
250 #else
251 TC_PRINT("Read bypassed\n");
252 #endif
253 ZCLOSE(&ts);
254 ZUNLINK(&ts);
255 ZEND();
256
257
258 ZBEGIN("Attempt open existing with R/W access");
259 ZMKEMPTY(&ts);
260 ZOPEN(&ts, FS_O_RDWR, 0);
261 ZWRITE(&ts, ts.write_size);
262 /* Read is done at the end of file, so 0 bytes will be read */
263 ZREAD(&ts, 0);
264 ZCLOSE(&ts);
265 ZUNLINK(&ts);
266 ZEND();
267
268
269 ZBEGIN("Attempt append existing with no R/W access");
270 ZMKEMPTY(&ts);
271 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_RW_IS_DEFAULT
272 ZOPEN(&ts, FS_O_APPEND, 0);
273 ZCHKPOS(&ts, 0);
274 ZWRITE(&ts, -EACCES);
275 ZREAD(&ts, -EACCES);
276 ZCLOSE(&ts);
277 #else
278 TC_PRINT("Test bypassed\n");
279 #endif
280 ZUNLINK(&ts);
281 ZEND();
282
283
284 ZBEGIN("Attempt append existing with READ access");
285 ZMKEMPTY(&ts);
286 ZOPEN(&ts, FS_O_APPEND | FS_O_READ, 0);
287 ZCHKPOS(&ts, 0);
288 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
289 ZWRITE(&ts, -EACCES);
290 #else
291 TC_PRINT("Write bypassed\n");
292 #endif
293 /* File is empty */
294 ZREAD(&ts, 0);
295 ZCLOSE(&ts);
296 ZUNLINK(&ts);
297 ZEND();
298
299
300 ZBEGIN("Attempt append existing with WRITE access");
301 ZMKEMPTY(&ts);
302 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, 0);
303 ZCHKPOS(&ts, 0);
304 ZWRITE(&ts, ts.write_size);
305 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
306 ZREAD(&ts, -EACCES);
307 #else
308 TC_PRINT("Read bypassed\n");
309 #endif
310 ZCLOSE(&ts);
311 ZUNLINK(&ts);
312 ZEND();
313
314
315 ZBEGIN("Attempt append existing with R/W access");
316 ZMKEMPTY(&ts);
317 ZOPEN(&ts, FS_O_APPEND | FS_O_RDWR, 0);
318 ZCHKPOS(&ts, 0);
319 ZWRITE(&ts, ts.write_size);
320 /* Read is done at the end of file, so 0 bytes will be read */
321 ZREAD(&ts, 0);
322 ZCLOSE(&ts);
323 ZUNLINK(&ts);
324 ZEND();
325
326 /** FS_O_TRUNC tests */
327 ZBEGIN("Attempt truncate a new file without write access");
328 ZOPEN(&ts, FS_O_CREATE | FS_O_TRUNC, -EACCES);
329 ZCLOSE(&ts);
330 ZUNLINK(&ts);
331 ZEND();
332
333 ZBEGIN("Attempt truncate a new file with write access");
334 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE | FS_O_TRUNC, 0);
335 ZCLOSE(&ts);
336 ZUNLINK(&ts);
337 ZEND();
338
339 ZBEGIN("Attempt truncate existing with no write access");
340 ZMKEMPTY(&ts);
341 ZOPEN(&ts, FS_O_TRUNC, -EACCES);
342 ZCLOSE(&ts);
343 ZUNLINK(&ts);
344 ZEND();
345
346 ZBEGIN("Attempt truncate existing with write access");
347 ZMKEMPTY(&ts);
348 ZOPEN(&ts, FS_O_TRUNC | FS_O_WRITE, 0);
349 ZCLOSE(&ts);
350 ZUNLINK(&ts);
351 ZEND();
352
353 ZBEGIN("Attempt truncate existing with read access");
354 ZMKEMPTY(&ts);
355 ZOPEN(&ts, FS_O_READ | FS_O_TRUNC, -EACCES);
356 ZCLOSE(&ts);
357 ZUNLINK(&ts);
358 ZEND();
359
360 ZBEGIN("Attempt truncate existing with R/W access");
361 ZMKEMPTY(&ts);
362 ZOPEN(&ts, FS_O_RDWR | FS_O_TRUNC, 0);
363 ZCLOSE(&ts);
364 ZUNLINK(&ts);
365 ZEND();
366
367 ZBEGIN("Attempt read on truncated file but no read access");
368 ZMKEMPTY(&ts);
369 ZOPEN(&ts, FS_O_WRITE | FS_O_TRUNC, 0);
370 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
371 ZREAD(&ts, -EACCES);
372 #else
373 TC_PRINT("Read bypassed\n");
374 #endif
375 ZCLOSE(&ts);
376 ZUNLINK(&ts);
377 ZEND();
378
379 ZBEGIN("Attempt append existing with WRITE access truncated file");
380 ZMKEMPTY(&ts);
381 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE | FS_O_TRUNC, 0);
382 ZCHKPOS(&ts, 0);
383 ZWRITE(&ts, ts.write_size);
384 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
385 ZREAD(&ts, -EACCES);
386 #else
387 TC_PRINT("Read bypassed\n");
388 #endif
389 ZCLOSE(&ts);
390 ZUNLINK(&ts);
391 ZEND();
392
393
394 /* This is simple check by file position, not contents. Since writing
395 * same pattern twice, the position of file should be twice the
396 * ts.write_size.
397 */
398 ZBEGIN("Check if append adds data to file");
399 /* Prepare file */
400 ZUNLINK(&ts);
401 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
402 ZWRITE(&ts, ts.write_size);
403 ZCLOSE(&ts);
404
405 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, 0);
406 ZCHKPOS(&ts, 0);
407 ZWRITE(&ts, ts.write_size);
408 ZCHKPOS(&ts, ts.write_size * 2);
409 ZCLOSE(&ts);
410 ZUNLINK(&ts);
411 ZEND();
412
413
414 ZBEGIN("Check if appended forwards file before write");
415 /* Prepare file */
416 ZUNLINK(&ts);
417 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
418 ZWRITE(&ts, ts.write_size);
419 ZCLOSE(&ts);
420
421 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, 0);
422 ZCHKPOS(&ts, 0);
423 ZREWIND(&ts);
424 ZWRITE(&ts, ts.write_size);
425 ZCHKPOS(&ts, ts.write_size * 2);
426 ZCLOSE(&ts);
427 ZUNLINK(&ts);
428 ZEND();
429
430
431 ZBEGIN("Check if file is truncated with data");
432 /* Prepare file */
433 ZUNLINK(&ts);
434 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
435 ZWRITE(&ts, ts.write_size);
436 ZCLOSE(&ts);
437
438 /* Make sure file has the content */
439 ZOPEN(&ts, FS_O_CREATE | FS_O_READ, 0);
440 ZREAD(&ts, ts.write_size);
441 ZCLOSE(&ts);
442
443 ZOPEN(&ts, FS_O_TRUNC | FS_O_RDWR, 0);
444 ZCHKPOS(&ts, 0);
445 ZREAD(&ts, 0);
446 ZCLOSE(&ts);
447 ZUNLINK(&ts);
448 ZEND();
449 }
450