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