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 = ®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 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