1 /*
2  * Copyright (c) 2018 Intel Corporation.
3  * Copyright (c) 2020 Peter Bigot Consulting, LLC
4  * Copyright (c) 2020-2024 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <zephyr/types.h>
12 #include <errno.h>
13 #include <zephyr/init.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/fs/fs.h>
16 #include <zephyr/fs/fs_sys.h>
17 #include <zephyr/sys/check.h>
18 
19 
20 #define LOG_LEVEL CONFIG_FS_LOG_LEVEL
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(fs);
23 
24 /* list of mounted file systems */
25 static sys_dlist_t fs_mnt_list = SYS_DLIST_STATIC_INIT(&fs_mnt_list);
26 
27 /* lock to protect mount list operations */
28 static K_MUTEX_DEFINE(mutex);
29 
30 /* Maps an identifier used in mount points to the file system
31  * implementation.
32  */
33 struct registry_entry {
34 	int type;
35 	const struct fs_file_system_t *fstp;
36 };
37 static struct registry_entry registry[CONFIG_FILE_SYSTEM_MAX_TYPES];
38 
registry_clear_entry(struct registry_entry * ep)39 static inline void registry_clear_entry(struct registry_entry *ep)
40 {
41 	ep->fstp = NULL;
42 }
43 
registry_add(int type,const struct fs_file_system_t * fstp)44 static int registry_add(int type,
45 			const struct fs_file_system_t *fstp)
46 {
47 	int rv = -ENOSPC;
48 
49 	for (size_t i = 0; i < ARRAY_SIZE(registry); ++i) {
50 		struct registry_entry *ep = &registry[i];
51 
52 		if (ep->fstp == NULL) {
53 			ep->type = type;
54 			ep->fstp = fstp;
55 			rv = 0;
56 			break;
57 		}
58 	}
59 
60 	return rv;
61 }
62 
registry_find(int type)63 static struct registry_entry *registry_find(int type)
64 {
65 	for (size_t i = 0; i < ARRAY_SIZE(registry); ++i) {
66 		struct registry_entry *ep = &registry[i];
67 
68 		if ((ep->fstp != NULL) && (ep->type == type)) {
69 			return ep;
70 		}
71 	}
72 	return NULL;
73 }
74 
fs_type_get(int type)75 static const struct fs_file_system_t *fs_type_get(int type)
76 {
77 	struct registry_entry *ep = registry_find(type);
78 
79 	return (ep != NULL) ? ep->fstp : NULL;
80 }
81 
fs_get_mnt_point(struct fs_mount_t ** mnt_pntp,const char * name,size_t * match_len)82 static int fs_get_mnt_point(struct fs_mount_t **mnt_pntp,
83 			    const char *name, size_t *match_len)
84 {
85 	struct fs_mount_t *mnt_p = NULL, *itr;
86 	size_t longest_match = 0;
87 	size_t len, name_len = strlen(name);
88 	sys_dnode_t *node;
89 
90 	k_mutex_lock(&mutex, K_FOREVER);
91 	SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
92 		itr = CONTAINER_OF(node, struct fs_mount_t, node);
93 		len = itr->mountp_len;
94 
95 		/*
96 		 * Move to next node if mount point length is
97 		 * shorter than longest_match match or if path
98 		 * name is shorter than the mount point name.
99 		 */
100 		if ((len < longest_match) || (len > name_len)) {
101 			continue;
102 		}
103 
104 		/*
105 		 * Move to next node if name does not have a directory
106 		 * separator where mount point name ends.
107 		 */
108 		if ((len > 1) && (name[len] != '/') && (name[len] != '\0')) {
109 			continue;
110 		}
111 
112 		/* Check for mount point match */
113 		if (strncmp(name, itr->mnt_point, len) == 0) {
114 			mnt_p = itr;
115 			longest_match = len;
116 		}
117 	}
118 	k_mutex_unlock(&mutex);
119 
120 	if (mnt_p == NULL) {
121 		return -ENOENT;
122 	}
123 
124 	*mnt_pntp = mnt_p;
125 	if (match_len) {
126 		*match_len = mnt_p->mountp_len;
127 	}
128 
129 	return 0;
130 }
131 
132 /* File operations */
fs_open(struct fs_file_t * zfp,const char * file_name,fs_mode_t flags)133 int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
134 {
135 	struct fs_mount_t *mp;
136 	int rc = -EINVAL;
137 	bool truncate_file = false;
138 
139 	if ((file_name == NULL) ||
140 			(strlen(file_name) <= 1) || (file_name[0] != '/')) {
141 		LOG_ERR("invalid file name!!");
142 		return -EINVAL;
143 	}
144 
145 	if (zfp->mp != NULL) {
146 		return -EBUSY;
147 	}
148 
149 	rc = fs_get_mnt_point(&mp, file_name, NULL);
150 	if (rc < 0) {
151 		LOG_ERR("mount point not found!!");
152 		return rc;
153 	}
154 
155 	if (((mp->flags & FS_MOUNT_FLAG_READ_ONLY) != 0) &&
156 	    (flags & FS_O_CREATE || flags & FS_O_WRITE)) {
157 		return -EROFS;
158 	}
159 
160 	CHECKIF(mp->fs->open == NULL) {
161 		return -ENOTSUP;
162 	}
163 
164 	if ((flags & FS_O_TRUNC) != 0) {
165 		if ((flags & FS_O_WRITE) == 0) {
166 			/** Truncate not allowed when file is not opened for write */
167 			LOG_ERR("file should be opened for write to truncate!!");
168 			return -EACCES;
169 		}
170 		CHECKIF(mp->fs->truncate == NULL) {
171 			LOG_ERR("file truncation not supported!!");
172 			return -ENOTSUP;
173 		}
174 		truncate_file = true;
175 	}
176 
177 	zfp->mp = mp;
178 	rc = mp->fs->open(zfp, file_name, flags);
179 	if (rc < 0) {
180 		LOG_ERR("file open error (%d)", rc);
181 		zfp->mp = NULL;
182 		return rc;
183 	}
184 
185 	/* Copy flags to zfp for use with other fs_ API calls */
186 	zfp->flags = flags;
187 
188 	if (truncate_file) {
189 		/* Truncate the opened file to 0 length */
190 		rc = mp->fs->truncate(zfp, 0);
191 		if (rc < 0) {
192 			LOG_ERR("file truncation failed (%d)", rc);
193 			zfp->mp = NULL;
194 			return rc;
195 		}
196 	}
197 
198 	return rc;
199 }
200 
fs_close(struct fs_file_t * zfp)201 int fs_close(struct fs_file_t *zfp)
202 {
203 	int rc = -EINVAL;
204 
205 	if (zfp->mp == NULL) {
206 		return 0;
207 	}
208 
209 	CHECKIF(zfp->mp->fs->close == NULL) {
210 		return -ENOTSUP;
211 	}
212 
213 	rc = zfp->mp->fs->close(zfp);
214 	if (rc < 0) {
215 		LOG_ERR("file close error (%d)", rc);
216 		return rc;
217 	}
218 
219 	zfp->mp = NULL;
220 
221 	return rc;
222 }
223 
fs_read(struct fs_file_t * zfp,void * ptr,size_t size)224 ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size)
225 {
226 	int rc = -EINVAL;
227 
228 	if (zfp->mp == NULL) {
229 		return -EBADF;
230 	}
231 
232 	CHECKIF(zfp->mp->fs->read == NULL) {
233 		return -ENOTSUP;
234 	}
235 
236 	rc = zfp->mp->fs->read(zfp, ptr, size);
237 	if (rc < 0) {
238 		LOG_ERR("file read error (%d)", rc);
239 	}
240 
241 	return rc;
242 }
243 
fs_write(struct fs_file_t * zfp,const void * ptr,size_t size)244 ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size)
245 {
246 	int rc = -EINVAL;
247 
248 	if (zfp->mp == NULL) {
249 		return -EBADF;
250 	}
251 
252 	CHECKIF(zfp->mp->fs->write == NULL) {
253 		return -ENOTSUP;
254 	}
255 
256 	rc = zfp->mp->fs->write(zfp, ptr, size);
257 	if (rc < 0) {
258 		LOG_ERR("file write error (%d)", rc);
259 	}
260 
261 	return rc;
262 }
263 
fs_seek(struct fs_file_t * zfp,off_t offset,int whence)264 int fs_seek(struct fs_file_t *zfp, off_t offset, int whence)
265 {
266 	int rc = -ENOTSUP;
267 
268 	if (zfp->mp == NULL) {
269 		return -EBADF;
270 	}
271 
272 	CHECKIF(zfp->mp->fs->lseek == NULL) {
273 		return -ENOTSUP;
274 	}
275 
276 	rc = zfp->mp->fs->lseek(zfp, offset, whence);
277 	if (rc < 0) {
278 		LOG_ERR("file seek error (%d)", rc);
279 	}
280 
281 	return rc;
282 }
283 
fs_tell(struct fs_file_t * zfp)284 off_t fs_tell(struct fs_file_t *zfp)
285 {
286 	int rc = -ENOTSUP;
287 
288 	if (zfp->mp == NULL) {
289 		return -EBADF;
290 	}
291 
292 	CHECKIF(zfp->mp->fs->tell == NULL) {
293 		return -ENOTSUP;
294 	}
295 
296 	rc = zfp->mp->fs->tell(zfp);
297 	if (rc < 0) {
298 		LOG_ERR("file tell error (%d)", rc);
299 	}
300 
301 	return rc;
302 }
303 
fs_truncate(struct fs_file_t * zfp,off_t length)304 int fs_truncate(struct fs_file_t *zfp, off_t length)
305 {
306 	int rc = -EINVAL;
307 
308 	if (zfp->mp == NULL) {
309 		return -EBADF;
310 	}
311 
312 	CHECKIF(zfp->mp->fs->truncate == NULL) {
313 		return -ENOTSUP;
314 	}
315 
316 	rc = zfp->mp->fs->truncate(zfp, length);
317 	if (rc < 0) {
318 		LOG_ERR("file truncate error (%d)", rc);
319 	}
320 
321 	return rc;
322 }
323 
fs_sync(struct fs_file_t * zfp)324 int fs_sync(struct fs_file_t *zfp)
325 {
326 	int rc = -EINVAL;
327 
328 	if (zfp->mp == NULL) {
329 		return -EBADF;
330 	}
331 
332 	CHECKIF(zfp->mp->fs->sync == NULL) {
333 		return -ENOTSUP;
334 	}
335 
336 	rc = zfp->mp->fs->sync(zfp);
337 	if (rc < 0) {
338 		LOG_ERR("file sync error (%d)", rc);
339 	}
340 
341 	return rc;
342 }
343 
344 /* Directory operations */
fs_opendir(struct fs_dir_t * zdp,const char * abs_path)345 int fs_opendir(struct fs_dir_t *zdp, const char *abs_path)
346 {
347 	struct fs_mount_t *mp;
348 	int rc = -EINVAL;
349 
350 	if ((abs_path == NULL) ||
351 			(strlen(abs_path) < 1) || (abs_path[0] != '/')) {
352 		LOG_ERR("invalid directory name!!");
353 		return -EINVAL;
354 	}
355 
356 	if (zdp->mp != NULL || zdp->dirp != NULL) {
357 		return -EBUSY;
358 	}
359 
360 
361 	if (strcmp(abs_path, "/") == 0) {
362 		/* Open VFS root dir, marked by zdp->mp == NULL */
363 		k_mutex_lock(&mutex, K_FOREVER);
364 
365 		zdp->mp = NULL;
366 		zdp->dirp = sys_dlist_peek_head(&fs_mnt_list);
367 
368 		k_mutex_unlock(&mutex);
369 
370 		return 0;
371 	}
372 
373 	rc = fs_get_mnt_point(&mp, abs_path, NULL);
374 	if (rc < 0) {
375 		LOG_ERR("mount point not found!!");
376 		return rc;
377 	}
378 
379 	CHECKIF(mp->fs->opendir == NULL) {
380 		return -ENOTSUP;
381 	}
382 
383 	zdp->mp = mp;
384 	rc = zdp->mp->fs->opendir(zdp, abs_path);
385 	if (rc < 0) {
386 		zdp->mp = NULL;
387 		zdp->dirp = NULL;
388 		LOG_ERR("directory open error (%d)", rc);
389 	}
390 
391 	return rc;
392 }
393 
fs_readdir(struct fs_dir_t * zdp,struct fs_dirent * entry)394 int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry)
395 {
396 	if (zdp->mp) {
397 		/* Delegate to mounted filesystem */
398 		int rc = -EINVAL;
399 
400 		CHECKIF(zdp->mp->fs->readdir == NULL) {
401 			return  -ENOTSUP;
402 		}
403 
404 		/* Loop until error or not special directory */
405 		while (true) {
406 			rc = zdp->mp->fs->readdir(zdp, entry);
407 			if (rc < 0) {
408 				break;
409 			}
410 			if (entry->name[0] == 0) {
411 				break;
412 			}
413 			if (entry->type != FS_DIR_ENTRY_DIR) {
414 				break;
415 			}
416 			if ((strcmp(entry->name, ".") != 0)
417 			    && (strcmp(entry->name, "..") != 0)) {
418 				break;
419 			}
420 		}
421 		if (rc < 0) {
422 			LOG_ERR("directory read error (%d)", rc);
423 		}
424 
425 		return rc;
426 	}
427 
428 	/* VFS root dir */
429 	if (zdp->dirp == NULL) {
430 		/* No more entries */
431 		entry->name[0] = 0;
432 		return 0;
433 	}
434 
435 	/* Find the current and next entries in the mount point dlist */
436 	sys_dnode_t *node, *next = NULL;
437 	bool found = false;
438 
439 	k_mutex_lock(&mutex, K_FOREVER);
440 
441 	SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
442 		if (node == zdp->dirp) {
443 			found = true;
444 
445 			/* Pull info from current entry */
446 			struct fs_mount_t *mnt;
447 
448 			mnt = CONTAINER_OF(node, struct fs_mount_t, node);
449 
450 			entry->type = FS_DIR_ENTRY_DIR;
451 			strncpy(entry->name, mnt->mnt_point + 1,
452 				sizeof(entry->name) - 1);
453 			entry->name[sizeof(entry->name) - 1] = 0;
454 			entry->size = 0;
455 
456 			/* Save pointer to the next one, for later */
457 			next = sys_dlist_peek_next(&fs_mnt_list, node);
458 			break;
459 		}
460 	}
461 
462 	k_mutex_unlock(&mutex);
463 
464 	if (!found) {
465 		/* Current entry must have been removed before this
466 		 * call to readdir -- return an error
467 		 */
468 		return -ENOENT;
469 	}
470 
471 	zdp->dirp = next;
472 	return 0;
473 }
474 
fs_closedir(struct fs_dir_t * zdp)475 int fs_closedir(struct fs_dir_t *zdp)
476 {
477 	int rc = -EINVAL;
478 
479 	if (zdp->mp == NULL) {
480 		/* VFS root dir */
481 		zdp->dirp = NULL;
482 		return 0;
483 	}
484 
485 	CHECKIF(zdp->mp->fs->closedir == NULL) {
486 		return -ENOTSUP;
487 	}
488 
489 	rc = zdp->mp->fs->closedir(zdp);
490 	if (rc < 0) {
491 		LOG_ERR("directory close error (%d)", rc);
492 		return rc;
493 	}
494 
495 	zdp->mp = NULL;
496 	zdp->dirp = NULL;
497 	return rc;
498 }
499 
500 /* Filesystem operations */
fs_mkdir(const char * abs_path)501 int fs_mkdir(const char *abs_path)
502 {
503 	struct fs_mount_t *mp;
504 	int rc = -EINVAL;
505 
506 	if ((abs_path == NULL) ||
507 			(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
508 		LOG_ERR("invalid directory name!!");
509 		return -EINVAL;
510 	}
511 
512 	rc = fs_get_mnt_point(&mp, abs_path, NULL);
513 	if (rc < 0) {
514 		LOG_ERR("mount point not found!!");
515 		return rc;
516 	}
517 
518 	if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
519 		return -EROFS;
520 	}
521 
522 	CHECKIF(mp->fs->mkdir == NULL) {
523 		return -ENOTSUP;
524 	}
525 
526 	rc = mp->fs->mkdir(mp, abs_path);
527 	if (rc < 0) {
528 		LOG_ERR("failed to create directory (%d)", rc);
529 	}
530 
531 	return rc;
532 }
533 
fs_unlink(const char * abs_path)534 int fs_unlink(const char *abs_path)
535 {
536 	struct fs_mount_t *mp;
537 	int rc = -EINVAL;
538 
539 	if ((abs_path == NULL) ||
540 			(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
541 		LOG_ERR("invalid file name!!");
542 		return -EINVAL;
543 	}
544 
545 	rc = fs_get_mnt_point(&mp, abs_path, NULL);
546 	if (rc < 0) {
547 		LOG_ERR("mount point not found!!");
548 		return rc;
549 	}
550 
551 	if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
552 		return -EROFS;
553 	}
554 
555 	CHECKIF(mp->fs->unlink == NULL) {
556 		return -ENOTSUP;
557 	}
558 
559 	rc = mp->fs->unlink(mp, abs_path);
560 	if (rc < 0) {
561 		LOG_ERR("failed to unlink path (%d)", rc);
562 	}
563 
564 	return rc;
565 }
566 
fs_rename(const char * from,const char * to)567 int fs_rename(const char *from, const char *to)
568 {
569 	struct fs_mount_t *mp;
570 	size_t match_len;
571 	int rc = -EINVAL;
572 
573 	if ((from == NULL) || (strlen(from) <= 1) || (from[0] != '/') ||
574 			(to == NULL) || (strlen(to) <= 1) || (to[0] != '/')) {
575 		LOG_ERR("invalid file name!!");
576 		return -EINVAL;
577 	}
578 
579 	rc = fs_get_mnt_point(&mp, from, &match_len);
580 	if (rc < 0) {
581 		LOG_ERR("mount point not found!!");
582 		return rc;
583 	}
584 
585 	if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
586 		return -EROFS;
587 	}
588 
589 	/* Make sure both files are mounted on the same path */
590 	if (strncmp(from, to, match_len) != 0) {
591 		LOG_ERR("mount point not same!!");
592 		return -EINVAL;
593 	}
594 
595 	CHECKIF(mp->fs->rename == NULL) {
596 		return -ENOTSUP;
597 	}
598 
599 	rc = mp->fs->rename(mp, from, to);
600 	if (rc < 0) {
601 		LOG_ERR("failed to rename file or dir (%d)", rc);
602 	}
603 
604 	return rc;
605 }
606 
fs_stat(const char * abs_path,struct fs_dirent * entry)607 int fs_stat(const char *abs_path, struct fs_dirent *entry)
608 {
609 	struct fs_mount_t *mp;
610 	int rc = -EINVAL;
611 
612 	if ((abs_path == NULL) ||
613 			(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
614 		LOG_ERR("invalid file or dir name!!");
615 		return -EINVAL;
616 	}
617 
618 	rc = fs_get_mnt_point(&mp, abs_path, NULL);
619 	if (rc < 0) {
620 		LOG_ERR("mount point not found!!");
621 		return rc;
622 	}
623 
624 	CHECKIF(mp->fs->stat == NULL) {
625 		return -ENOTSUP;
626 	}
627 
628 	rc = mp->fs->stat(mp, abs_path, entry);
629 	if (rc == -ENOENT) {
630 		/* File doesn't exist, which is a valid stat response */
631 	} else if (rc < 0) {
632 		LOG_ERR("failed get file or dir stat (%d)", rc);
633 	}
634 	return rc;
635 }
636 
fs_statvfs(const char * abs_path,struct fs_statvfs * stat)637 int fs_statvfs(const char *abs_path, struct fs_statvfs *stat)
638 {
639 	struct fs_mount_t *mp;
640 	int rc;
641 
642 	if ((abs_path == NULL) ||
643 			(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
644 		LOG_ERR("invalid file or dir name!!");
645 		return -EINVAL;
646 	}
647 
648 	rc = fs_get_mnt_point(&mp, abs_path, NULL);
649 	if (rc < 0) {
650 		LOG_ERR("mount point not found!!");
651 		return rc;
652 	}
653 
654 	CHECKIF(mp->fs->statvfs == NULL) {
655 		return -ENOTSUP;
656 	}
657 
658 	rc = mp->fs->statvfs(mp, abs_path, stat);
659 	if (rc < 0) {
660 		LOG_ERR("failed get file or dir stat (%d)", rc);
661 	}
662 
663 	return rc;
664 }
665 
fs_mount(struct fs_mount_t * mp)666 int fs_mount(struct fs_mount_t *mp)
667 {
668 	struct fs_mount_t *itr;
669 	const struct fs_file_system_t *fs;
670 	sys_dnode_t *node;
671 	int rc = -EINVAL;
672 	size_t len = 0;
673 
674 	/* Do all the mp checks prior to locking the mutex on the file
675 	 * subsystem.
676 	 */
677 	if ((mp == NULL) || (mp->mnt_point == NULL)) {
678 		LOG_ERR("mount point not initialized!!");
679 		return -EINVAL;
680 	}
681 
682 	if (sys_dnode_is_linked(&mp->node)) {
683 		LOG_ERR("file system already mounted!!");
684 		return -EBUSY;
685 	}
686 
687 	len = strlen(mp->mnt_point);
688 
689 	if ((len <= 1) || (mp->mnt_point[0] != '/')) {
690 		LOG_ERR("invalid mount point!!");
691 		return -EINVAL;
692 	}
693 
694 	k_mutex_lock(&mutex, K_FOREVER);
695 
696 	/* Check if mount point already exists */
697 	SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
698 		itr = CONTAINER_OF(node, struct fs_mount_t, node);
699 		/* continue if length does not match */
700 		if (len != itr->mountp_len) {
701 			continue;
702 		}
703 
704 		CHECKIF(mp->fs_data == itr->fs_data) {
705 			LOG_ERR("file system already mounted!!");
706 			rc = -EBUSY;
707 			goto mount_err;
708 		}
709 
710 		if (strncmp(mp->mnt_point, itr->mnt_point, len) == 0) {
711 			LOG_ERR("mount point already exists!!");
712 			rc = -EBUSY;
713 			goto mount_err;
714 		}
715 	}
716 
717 	/* Get file system information */
718 	fs = fs_type_get(mp->type);
719 	if (fs == NULL) {
720 		LOG_ERR("requested file system type not registered!!");
721 		rc = -ENOENT;
722 		goto mount_err;
723 	}
724 
725 	CHECKIF(fs->mount == NULL) {
726 		LOG_ERR("fs type %d does not support mounting", mp->type);
727 		rc = -ENOTSUP;
728 		goto mount_err;
729 	}
730 
731 	if (fs->unmount == NULL) {
732 		LOG_WRN("mount path %s is not unmountable",
733 			mp->mnt_point);
734 	}
735 
736 	rc = fs->mount(mp);
737 	if (rc < 0) {
738 		LOG_ERR("fs mount error (%d)", rc);
739 		goto mount_err;
740 	}
741 
742 	/* Update mount point data and append it to the list */
743 	mp->mountp_len = len;
744 	mp->fs = fs;
745 
746 	sys_dlist_append(&fs_mnt_list, &mp->node);
747 	LOG_DBG("fs mounted at %s", mp->mnt_point);
748 
749 mount_err:
750 	k_mutex_unlock(&mutex);
751 	return rc;
752 }
753 
754 #if defined(CONFIG_FILE_SYSTEM_MKFS)
755 
fs_mkfs(int fs_type,uintptr_t dev_id,void * cfg,int flags)756 int fs_mkfs(int fs_type, uintptr_t dev_id, void *cfg, int flags)
757 {
758 	int rc = -EINVAL;
759 	const struct fs_file_system_t *fs;
760 
761 	k_mutex_lock(&mutex, K_FOREVER);
762 
763 	/* Get file system information */
764 	fs = fs_type_get(fs_type);
765 	if (fs == NULL) {
766 		LOG_ERR("fs type %d not registered!!",
767 				fs_type);
768 		rc = -ENOENT;
769 		goto mount_err;
770 	}
771 
772 	CHECKIF(fs->mkfs == NULL) {
773 		LOG_ERR("fs type %d does not support mkfs", fs_type);
774 		rc = -ENOTSUP;
775 		goto mount_err;
776 	}
777 
778 	rc = fs->mkfs(dev_id, cfg, flags);
779 	if (rc < 0) {
780 		LOG_ERR("mkfs error (%d)", rc);
781 		goto mount_err;
782 	}
783 
784 mount_err:
785 	k_mutex_unlock(&mutex);
786 	return rc;
787 }
788 
789 #endif /* CONFIG_FILE_SYSTEM_MKFS */
790 
fs_unmount(struct fs_mount_t * mp)791 int fs_unmount(struct fs_mount_t *mp)
792 {
793 	int rc = -EINVAL;
794 
795 	if (mp == NULL) {
796 		return rc;
797 	}
798 
799 	k_mutex_lock(&mutex, K_FOREVER);
800 
801 	if (!sys_dnode_is_linked(&mp->node)) {
802 		LOG_ERR("fs not mounted (mp == %p)", mp);
803 		goto unmount_err;
804 	}
805 
806 	CHECKIF(mp->fs->unmount == NULL) {
807 		LOG_ERR("fs unmount not supported!!");
808 		rc = -ENOTSUP;
809 		goto unmount_err;
810 	}
811 
812 	rc = mp->fs->unmount(mp);
813 	if (rc < 0) {
814 		LOG_ERR("fs unmount error (%d)", rc);
815 		goto unmount_err;
816 	}
817 
818 	/* clear file system interface */
819 	mp->fs = NULL;
820 
821 	/* remove mount node from the list */
822 	sys_dlist_remove(&mp->node);
823 	LOG_DBG("fs unmounted from %s", mp->mnt_point);
824 
825 unmount_err:
826 	k_mutex_unlock(&mutex);
827 	return rc;
828 }
829 
fs_readmount(int * index,const char ** name)830 int fs_readmount(int *index, const char **name)
831 {
832 	sys_dnode_t *node;
833 	int rc = -ENOENT;
834 	int cnt = 0;
835 	struct fs_mount_t *itr = NULL;
836 
837 	*name = NULL;
838 
839 	k_mutex_lock(&mutex, K_FOREVER);
840 
841 	SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
842 		if (*index == cnt) {
843 			itr = CONTAINER_OF(node, struct fs_mount_t, node);
844 			break;
845 		}
846 
847 		++cnt;
848 	}
849 
850 	k_mutex_unlock(&mutex);
851 
852 	if (itr != NULL) {
853 		rc = 0;
854 		*name = itr->mnt_point;
855 		++(*index);
856 	}
857 
858 	return rc;
859 
860 }
861 
862 /* Register File system */
fs_register(int type,const struct fs_file_system_t * fs)863 int fs_register(int type, const struct fs_file_system_t *fs)
864 {
865 	int rc = 0;
866 
867 	k_mutex_lock(&mutex, K_FOREVER);
868 
869 	if (fs_type_get(type) != NULL) {
870 		rc = -EALREADY;
871 	} else {
872 		rc = registry_add(type, fs);
873 	}
874 
875 	k_mutex_unlock(&mutex);
876 
877 	LOG_DBG("fs register %d: %d", type, rc);
878 
879 	return rc;
880 }
881 
882 /* Unregister File system */
fs_unregister(int type,const struct fs_file_system_t * fs)883 int fs_unregister(int type, const struct fs_file_system_t *fs)
884 {
885 	int rc = 0;
886 	struct registry_entry *ep;
887 
888 	k_mutex_lock(&mutex, K_FOREVER);
889 
890 	ep = registry_find(type);
891 	if ((ep == NULL) || (ep->fstp != fs)) {
892 		rc = -EINVAL;
893 	} else {
894 		registry_clear_entry(ep);
895 	}
896 
897 	k_mutex_unlock(&mutex);
898 
899 	LOG_DBG("fs unregister %d: %d", type, rc);
900 	return rc;
901 }
902