1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8 #include <fcntl.h>
9 #include <zephyr/posix/unistd.h>
10 #include "test_fs.h"
11
12 const char test_str[] = "hello world!";
13 int file = -1;
14
test_file_open(void)15 static int test_file_open(void)
16 {
17 int res;
18
19 res = open(TEST_FILE, O_CREAT | O_RDWR);
20 if (res < 0) {
21 TC_ERROR("Failed opening file: %d, errno=%d\n", res, errno);
22 /* FIXME: restructure tests as per #46897 */
23 __ASSERT_NO_MSG(res >= 0);
24 }
25
26 file = res;
27
28 return TC_PASS;
29 }
30
test_file_write(void)31 int test_file_write(void)
32 {
33 ssize_t brw;
34 off_t res;
35
36 res = lseek(file, 0, SEEK_SET);
37 if (res != 0) {
38 TC_PRINT("lseek failed [%d]\n", (int)res);
39 close(file);
40 file = -1;
41 return TC_FAIL;
42 }
43
44 brw = write(file, (char *)test_str, strlen(test_str));
45 if (brw < 0) {
46 TC_PRINT("Failed writing to file [%d]\n", (int)brw);
47 close(file);
48 file = -1;
49 return TC_FAIL;
50 }
51
52 if (brw < strlen(test_str)) {
53 TC_PRINT("Unable to complete write. Volume full.\n");
54 TC_PRINT("Number of bytes written: [%d]\n", (int)brw);
55 close(file);
56 file = -1;
57 return TC_FAIL;
58 }
59
60 return res;
61 }
62
test_file_read(void)63 static int test_file_read(void)
64 {
65 ssize_t brw;
66 off_t res;
67 char read_buff[80];
68 size_t sz = strlen(test_str);
69
70 res = lseek(file, 0, SEEK_SET);
71 if (res != 0) {
72 TC_PRINT("lseek failed [%d]\n", (int)res);
73 close(file);
74 file = -1;
75 return TC_FAIL;
76 }
77
78 brw = read(file, read_buff, sz);
79 if (brw < 0) {
80 TC_PRINT("Failed reading file [%d]\n", (int)brw);
81 close(file);
82 file = -1;
83 return TC_FAIL;
84 }
85
86 read_buff[brw] = 0;
87
88 if (strcmp(test_str, read_buff)) {
89 TC_PRINT("Error - Data read does not match data written\n");
90 TC_PRINT("Data read:\"%s\"\n\n", read_buff);
91 return TC_FAIL;
92 }
93
94 /* Now test after non-zero lseek. */
95
96 res = lseek(file, 2, SEEK_SET);
97 if (res != 2) {
98 TC_PRINT("lseek failed [%d]\n", (int)res);
99 close(file);
100 file = -1;
101 return TC_FAIL;
102 }
103
104 brw = read(file, read_buff, sizeof(read_buff));
105 if (brw < 0) {
106 TC_PRINT("Failed reading file [%d]\n", (int)brw);
107 close(file);
108 file = -1;
109 return TC_FAIL;
110 }
111
112 /* Check for array overrun */
113 brw = (brw < 80) ? brw : brw - 1;
114
115 read_buff[brw] = 0;
116
117 if (strcmp(test_str + 2, read_buff)) {
118 TC_PRINT("Error - Data read does not match data written\n");
119 TC_PRINT("Data read:\"%s\"\n\n", read_buff);
120 return TC_FAIL;
121 }
122
123 return TC_PASS;
124 }
125
test_file_close(void)126 static int test_file_close(void)
127 {
128 int res = 0;
129
130 if (file >= 0) {
131 res = close(file);
132 if (res < 0) {
133 TC_ERROR("Failed closing file: %d, errno=%d\n", res, errno);
134 /* FIXME: restructure tests as per #46897 */
135 __ASSERT_NO_MSG(res == 0);
136 }
137
138 file = -1;
139 }
140
141 return res;
142 }
143
test_file_fsync(void)144 static int test_file_fsync(void)
145 {
146 int res = 0;
147
148 if (file < 0)
149 return res;
150
151 res = fsync(file);
152 if (res < 0) {
153 TC_ERROR("Failed to sync file: %d, errno = %d\n", res, errno);
154 res = TC_FAIL;
155 }
156
157 close(file);
158 file = -1;
159 return res;
160 }
161
162 #ifdef CONFIG_POSIX_SYNCHRONIZED_IO
test_file_fdatasync(void)163 static int test_file_fdatasync(void)
164 {
165 int res = 0;
166
167 if (file < 0)
168 return res;
169
170 res = fdatasync(file);
171 if (res < 0) {
172 TC_ERROR("Failed to sync file: %d, errno = %d\n", res, errno);
173 res = TC_FAIL;
174 }
175
176 close(file);
177 file = -1;
178 return res;
179 }
180 #endif /* CONFIG_POSIX_SYNCHRONIZED_IO */
181
test_file_truncate(void)182 static int test_file_truncate(void)
183 {
184 int res = 0;
185 size_t truncate_size = sizeof(test_str) - 4;
186
187 if (file < 0)
188 return res;
189
190 res = ftruncate(file, truncate_size);
191 if (res) {
192 TC_PRINT("Error truncating file [%d]\n", res);
193 res = TC_FAIL;
194 }
195
196 close(file);
197 file = -1;
198 return res;
199 }
200
test_file_delete(void)201 static int test_file_delete(void)
202 {
203 int res;
204
205 res = unlink(TEST_FILE);
206 if (res) {
207 TC_PRINT("Error deleting file [%d]\n", res);
208 return res;
209 }
210
211 return res;
212 }
213
after_fn(void * unused)214 static void after_fn(void *unused)
215 {
216 ARG_UNUSED(unused);
217
218 test_file_close();
219 unlink(TEST_FILE);
220 }
221
222 ZTEST_SUITE(posix_fs_file_test, NULL, test_mount, NULL, after_fn,
223 test_unmount);
224
225 /**
226 * @brief Test for POSIX open API
227 *
228 * @details Test opens new file through POSIX open API.
229 */
ZTEST(posix_fs_file_test,test_fs_open)230 ZTEST(posix_fs_file_test, test_fs_open)
231 {
232 /* FIXME: restructure tests as per #46897 */
233 zassert_true(test_file_open() == TC_PASS);
234 }
235
236 /**
237 * @brief Test for POSIX write API
238 *
239 * @details Test writes some data through POSIX write API.
240 */
ZTEST(posix_fs_file_test,test_fs_write)241 ZTEST(posix_fs_file_test, test_fs_write)
242 {
243 /* FIXME: restructure tests as per #46897 */
244 zassert_true(test_file_open() == TC_PASS);
245 zassert_true(test_file_write() == TC_PASS);
246 }
247
248 /**
249 * @brief Test for POSIX write API
250 *
251 * @details Test reads data back through POSIX read API.
252 */
ZTEST(posix_fs_file_test,test_fs_read)253 ZTEST(posix_fs_file_test, test_fs_read)
254 {
255 /* FIXME: restructure tests as per #46897 */
256 zassert_true(test_file_open() == TC_PASS);
257 zassert_true(test_file_write() == TC_PASS);
258 zassert_true(test_file_read() == TC_PASS);
259 }
260
261 /**
262 * @brief Test for POSIX fsync API
263 *
264 * @details Test sync the file through POSIX fsync API.
265 */
ZTEST(posix_fs_file_test,test_fs_sync)266 ZTEST(posix_fs_file_test, test_fs_sync)
267 {
268 /* FIXME: restructure tests as per #46897 */
269 zassert_true(test_file_open() == TC_PASS);
270 zassert_true(test_file_write() == TC_PASS);
271 zassert_true(test_file_fsync() == TC_PASS);
272 }
273
274 /**
275 * @brief Test for POSIX fdatasync API
276 *
277 * @details Test sync the file through POSIX fdatasync API.
278 */
ZTEST(posix_fs_file_test,test_fs_datasync)279 ZTEST(posix_fs_file_test, test_fs_datasync)
280 {
281 #ifdef CONFIG_POSIX_SYNCHRONIZED_IO
282 /* FIXME: restructure tests as per #46897 */
283 zassert_true(test_file_open() == TC_PASS);
284 zassert_true(test_file_write() == TC_PASS);
285 zassert_true(test_file_fdatasync() == TC_PASS);
286 #else
287 ztest_test_skip();
288 #endif
289 }
290
291 /**
292 * @brief Test for POSIX ftruncate API
293 *
294 * @details Test truncate the file through POSIX ftruncate API.
295 */
ZTEST(posix_fs_file_test,test_fs_truncate)296 ZTEST(posix_fs_file_test, test_fs_truncate)
297 {
298 /* FIXME: restructure tests as per #46897 */
299 zassert_true(test_file_open() == TC_PASS);
300 zassert_true(test_file_write() == TC_PASS);
301 zassert_true(test_file_truncate() == TC_PASS);
302 }
303
304 /**
305 * @brief Test for POSIX close API
306 *
307 * @details Test closes the open file through POSIX close API.
308 */
ZTEST(posix_fs_file_test,test_fs_close)309 ZTEST(posix_fs_file_test, test_fs_close)
310 {
311 /* FIXME: restructure tests as per #46897 */
312 zassert_true(test_file_open() == TC_PASS);
313 zassert_true(test_file_close() == TC_PASS);
314 }
315
316 /**
317 * @brief Test for POSIX unlink API
318 *
319 * @details Test deletes a file through POSIX unlink API.
320 */
ZTEST(posix_fs_file_test,test_fs_unlink)321 ZTEST(posix_fs_file_test, test_fs_unlink)
322 {
323 zassert_true(test_file_open() == TC_PASS);
324 zassert_true(test_file_delete() == TC_PASS);
325 }
326
ZTEST(posix_fs_file_test,test_fs_fd_leak)327 ZTEST(posix_fs_file_test, test_fs_fd_leak)
328 {
329 const int reps =
330 MAX(CONFIG_POSIX_OPEN_MAX, CONFIG_ZVFS_OPEN_MAX) + 5;
331
332 for (int i = 0; i < reps; i++) {
333 if (i > 0) {
334 zassert_true(test_file_open() == TC_PASS);
335 }
336
337 if (i < reps - 1) {
338 zassert_true(test_file_close() == TC_PASS);
339 }
340 }
341 }
342