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