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