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