1 /*
2  * Copyright (c) 2020 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/types.h>
11 #include <errno.h>
12 #include <zephyr/init.h>
13 #include <zephyr/fs/fs.h>
14 #include <zephyr/fs/fs_sys.h>
15 #include <zephyr/sys/__assert.h>
16 #include "test_fs.h"
17 
18 #define BUF_LEN 128
19 static char buffer[BUF_LEN];
20 static char *read_pos = buffer;
21 static char *cur = buffer;
22 static int file_length;
23 static struct fs_mount_t *mp[FS_TYPE_EXTERNAL_BASE];
24 static bool nospace;
25 static int opendir_result;
26 
27 static
temp_open(struct fs_file_t * zfp,const char * file_name,fs_mode_t flags)28 int temp_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
29 {
30 	if (zfp == NULL || file_name == NULL) {
31 		return -EINVAL;
32 	}
33 
34 	if (zfp->filep) {
35 		if (strcmp(zfp->filep, file_name) == 0) {
36 			/* file has been opened */
37 			return -EEXIST;
38 		}
39 	}
40 
41 	if (!(flags & FS_O_MASK)) {
42 		return -EINVAL;
43 	}
44 
45 	zfp->filep = (char *)file_name;
46 	return 0;
47 }
48 
temp_close(struct fs_file_t * zfp)49 static int temp_close(struct fs_file_t *zfp)
50 {
51 	if (zfp == NULL) {
52 		return -EINVAL;
53 	}
54 
55 	if (zfp->filep) {
56 		zfp->filep = NULL;
57 	} else {
58 		return -EIO;
59 	}
60 
61 	return 0;
62 }
63 
temp_unlink(struct fs_mount_t * mountp,const char * path)64 static int temp_unlink(struct fs_mount_t *mountp, const char *path)
65 {
66 	if (mountp == NULL || path == NULL) {
67 		return -EINVAL;
68 	}
69 
70 	if (strcmp(mountp->mnt_point, path) == 0) {
71 		return -EPERM;
72 	}
73 	return 0;
74 }
75 
temp_rename(struct fs_mount_t * mountp,const char * from,const char * to)76 static int temp_rename(struct fs_mount_t *mountp, const char *from,
77 			const char *to)
78 {
79 	if (mountp == NULL || from == NULL || to == NULL) {
80 		return -EINVAL;
81 	}
82 
83 	if (strcmp(to, TEST_FILE_EX) == 0) {
84 		return -EINVAL;
85 	}
86 	return 0;
87 }
88 
temp_read(struct fs_file_t * zfp,void * ptr,size_t size)89 static ssize_t temp_read(struct fs_file_t *zfp, void *ptr, size_t size)
90 {
91 	unsigned int br;
92 
93 	if (zfp == NULL || ptr == NULL) {
94 		return -EINVAL;
95 	}
96 
97 	br = size;
98 	if (read_pos - buffer + br > file_length) {
99 		br = file_length - (read_pos - buffer);
100 	}
101 	memcpy(ptr, read_pos, br);
102 	read_pos += br;
103 	cur = read_pos;
104 
105 	return br;
106 }
107 
temp_write(struct fs_file_t * zfp,const void * ptr,size_t size)108 static ssize_t temp_write(struct fs_file_t *zfp, const void *ptr, size_t size)
109 {
110 	unsigned int bw;
111 
112 	if (zfp == NULL || ptr == NULL) {
113 		return -EINVAL;
114 	}
115 
116 	if (nospace) {
117 		return -ENOSPC;
118 	}
119 
120 	bw = size;
121 	if (file_length + bw >  BUF_LEN) {
122 		bw = BUF_LEN - file_length;
123 		nospace = true;
124 	}
125 
126 	memcpy(buffer + file_length, ptr, bw);
127 	file_length += bw;
128 	cur = buffer + file_length;
129 
130 	return bw;
131 }
132 
temp_seek(struct fs_file_t * zfp,off_t offset,int whence)133 static int temp_seek(struct fs_file_t *zfp, off_t offset, int whence)
134 {
135 
136 	if (!zfp) {
137 		return -EINVAL;
138 	}
139 
140 	switch (whence) {
141 	case FS_SEEK_SET:
142 		cur = buffer + offset;
143 		break;
144 	case FS_SEEK_CUR:
145 		cur += offset;
146 		break;
147 	case FS_SEEK_END:
148 		cur = buffer + file_length + offset;
149 		break;
150 	default:
151 		return -EINVAL;
152 	}
153 
154 	if ((cur < buffer) || (cur > buffer + file_length)) {
155 		return -EINVAL;
156 	}
157 
158 	return 0;
159 }
160 
temp_tell(struct fs_file_t * zfp)161 static off_t temp_tell(struct fs_file_t *zfp)
162 {
163 	if (!zfp) {
164 		return -EINVAL;
165 	}
166 
167 	if (nospace) {
168 		return -ENOSPC;
169 	}
170 
171 	return cur - buffer;
172 }
173 
temp_truncate(struct fs_file_t * zfp,off_t length)174 static int temp_truncate(struct fs_file_t *zfp, off_t length)
175 {
176 	if (!zfp) {
177 		return -EINVAL;
178 	}
179 
180 	if (length > BUF_LEN) {
181 		return -EINVAL;
182 	}
183 	file_length = length;
184 	return 0;
185 }
186 
temp_sync(struct fs_file_t * zfp)187 static int temp_sync(struct fs_file_t *zfp)
188 {
189 	if (!zfp) {
190 		return -EINVAL;
191 	}
192 
193 	if (nospace) {
194 		return -ENOSPC;
195 	}
196 
197 	return 0;
198 }
199 
temp_mkdir(struct fs_mount_t * mountp,const char * path)200 static int temp_mkdir(struct fs_mount_t *mountp, const char *path)
201 {
202 	if (mountp == NULL || path == NULL) {
203 		return -EINVAL;
204 	}
205 
206 	if (strcmp(mountp->mnt_point, path) == 0) {
207 		return -EPERM;
208 	}
209 	return 0;
210 }
211 
mock_opendir_result(int ret)212 void mock_opendir_result(int ret)
213 {
214 	opendir_result = ret;
215 }
216 
temp_opendir(struct fs_dir_t * zdp,const char * path)217 static int temp_opendir(struct fs_dir_t *zdp, const char *path)
218 {
219 	if (zdp == NULL || path == NULL) {
220 		return -EINVAL;
221 	}
222 
223 	if (opendir_result) {
224 		return opendir_result;
225 	}
226 
227 	zdp->dirp = (char *)path;
228 	return 0;
229 }
230 
231 static int i;
temp_readdir(struct fs_dir_t * zdp,struct fs_dirent * entry)232 static int temp_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry)
233 {
234 	if (!zdp) {
235 		return -EINVAL;
236 	}
237 
238 	if (!entry) {
239 		return -ENOENT;
240 	}
241 
242 	switch (i) {
243 	case 0:
244 		strcpy(entry->name, ".");
245 		entry->type = FS_DIR_ENTRY_DIR;
246 		i++;
247 		break;
248 	case 1:
249 		strcpy(entry->name, "testdir");
250 		entry->type = FS_DIR_ENTRY_DIR;
251 		i++;
252 		break;
253 	case 2:
254 		strcpy(entry->name, "test.txt");
255 		entry->type = FS_DIR_ENTRY_FILE;
256 		i++;
257 		break;
258 	case 3:
259 		strcpy(entry->name, "..");
260 		entry->type = FS_DIR_ENTRY_DIR;
261 		i++;
262 		break;
263 	default:
264 		strcpy(entry->name, "\0");
265 		i = 0;
266 		break;
267 	}
268 	return 0;
269 }
270 
temp_closedir(struct fs_dir_t * zdp)271 static int temp_closedir(struct fs_dir_t *zdp)
272 {
273 	if (!zdp) {
274 		return -EINVAL;
275 	}
276 
277 	if (!(zdp->dirp)) {
278 		return -EIO;
279 	}
280 	zdp->dirp = NULL;
281 	return 0;
282 }
283 
temp_stat(struct fs_mount_t * mountp,const char * path,struct fs_dirent * entry)284 static int temp_stat(struct fs_mount_t *mountp,
285 		      const char *path, struct fs_dirent *entry)
286 {
287 	if (mountp == NULL || path == NULL || entry == NULL) {
288 		return -EINVAL;
289 	}
290 
291 	return 0;
292 }
293 
temp_statvfs(struct fs_mount_t * mountp,const char * path,struct fs_statvfs * stat)294 static int temp_statvfs(struct fs_mount_t *mountp,
295 			 const char *path, struct fs_statvfs *stat)
296 {
297 	if (mountp == NULL || path == NULL || stat == NULL) {
298 		return -EINVAL;
299 	}
300 
301 	memset(stat, 0, sizeof(struct fs_statvfs));
302 	stat->f_bsize = 512;
303 	return 0;
304 }
305 
temp_mount(struct fs_mount_t * mountp)306 static int temp_mount(struct fs_mount_t *mountp)
307 {
308 	if (mountp == NULL) {
309 		return -EINVAL;
310 	}
311 
312 	size_t len = strlen(mountp->mnt_point);
313 
314 	if (mountp->mnt_point[len - 1] != ':') {
315 		return -EINVAL;
316 	}
317 	mp[mountp->type] = mountp;
318 	return 0;
319 }
320 
temp_unmount(struct fs_mount_t * mountp)321 static int temp_unmount(struct fs_mount_t *mountp)
322 {
323 	if (mountp == NULL) {
324 		return -EINVAL;
325 	}
326 
327 	if (mp[mountp->type] == NULL) {
328 		return -EINVAL;
329 	}
330 	mp[mountp->type] = NULL;
331 	return 0;
332 }
333 
334 /* File system interface */
335 struct fs_file_system_t temp_fs = {
336 	.open = temp_open,
337 	.close = temp_close,
338 	.read = temp_read,
339 	.write = temp_write,
340 	.lseek = temp_seek,
341 	.tell = temp_tell,
342 	.truncate = temp_truncate,
343 	.sync = temp_sync,
344 	.opendir = temp_opendir,
345 	.readdir = temp_readdir,
346 	.closedir = temp_closedir,
347 	.mount = temp_mount,
348 	.unmount = temp_unmount,
349 	.unlink = temp_unlink,
350 	.rename = temp_rename,
351 	.mkdir = temp_mkdir,
352 	.stat = temp_stat,
353 	.statvfs = temp_statvfs,
354 };
355