blob: 5df0c13236b3d90e301ea894d529e226b8ad66e7 [file] [log] [blame]
Ramakrishna Pallala25302b12018-02-22 13:32:57 +05301/*
2 * Copyright (c) 2018 Intel Corporation.
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -05003 * Copyright (c) 2020 Peter Bigot Consulting, LLC
Dominik Ermel07c1e492023-10-19 16:53:17 +00004 * Copyright (c) 2020-2024 Nordic Semiconductor ASA
Ramakrishna Pallala25302b12018-02-22 13:32:57 +05305 *
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>
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020013#include <zephyr/init.h>
Gerard Marull-Paretas6a0f5542022-10-04 16:34:24 +020014#include <zephyr/kernel.h>
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020015#include <zephyr/fs/fs.h>
16#include <zephyr/fs/fs_sys.h>
17#include <zephyr/sys/check.h>
Ramakrishna Pallala25302b12018-02-22 13:32:57 +053018
Gerard Marull-Paretas5113c142022-05-06 11:12:04 +020019#include <zephyr/logging/log.h>
Kiara Navarro9207a1b2025-03-24 19:48:02 -030020LOG_MODULE_REGISTER(fs, CONFIG_FS_LOG_LEVEL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +053021
22/* list of mounted file systems */
Miika Karanki89d4f062024-01-19 10:18:34 +020023static sys_dlist_t fs_mnt_list = SYS_DLIST_STATIC_INIT(&fs_mnt_list);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +053024
25/* lock to protect mount list operations */
Miika Karanki89d4f062024-01-19 10:18:34 +020026static K_MUTEX_DEFINE(mutex);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +053027
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -050028/* Maps an identifier used in mount points to the file system
29 * implementation.
30 */
31struct registry_entry {
32 int type;
33 const struct fs_file_system_t *fstp;
34};
35static struct registry_entry registry[CONFIG_FILE_SYSTEM_MAX_TYPES];
36
37static inline void registry_clear_entry(struct registry_entry *ep)
38{
39 ep->fstp = NULL;
40}
41
42static 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
61static 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
73static 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}
Ramakrishna Pallala25302b12018-02-22 13:32:57 +053079
Peter A. Bigot4d8726a2019-07-23 12:31:40 -050080static int fs_get_mnt_point(struct fs_mount_t **mnt_pntp,
81 const char *name, size_t *match_len)
Ramakrishna Pallala25302b12018-02-22 13:32:57 +053082{
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;
Anas Nashif718750f2022-07-06 08:05:26 -0400123 if (match_len) {
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530124 *match_len = mnt_p->mountp_len;
Anas Nashif718750f2022-07-06 08:05:26 -0400125 }
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530126
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530127 return 0;
128}
129
130/* File operations */
Dominik Ermelcac07622020-06-18 09:16:35 +0000131int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530132{
133 struct fs_mount_t *mp;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530134 int rc = -EINVAL;
RAJAGOPALAN GANGADHARAN65c4ca12024-05-21 23:42:16 +0530135 bool truncate_file = false;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530136
137 if ((file_name == NULL) ||
138 (strlen(file_name) <= 1) || (file_name[0] != '/')) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530139 LOG_ERR("invalid file name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530140 return -EINVAL;
141 }
142
Dominik Ermeld4666f52021-01-25 16:27:57 +0000143 if (zfp->mp != NULL) {
144 return -EBUSY;
145 }
146
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530147 rc = fs_get_mnt_point(&mp, file_name, NULL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530148 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200149 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530150 return rc;
151 }
152
Dominik Ermelaa0fd022020-10-08 11:36:57 +0000153 if (((mp->flags & FS_MOUNT_FLAG_READ_ONLY) != 0) &&
154 (flags & FS_O_CREATE || flags & FS_O_WRITE)) {
155 return -EROFS;
156 }
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530157
Dominik Ermeld4666f52021-01-25 16:27:57 +0000158 CHECKIF(mp->fs->open == NULL) {
Dominik Ermel045900e2020-10-21 13:02:49 +0000159 return -ENOTSUP;
160 }
161
RAJAGOPALAN GANGADHARAN65c4ca12024-05-21 23:42:16 +0530162 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
Dominik Ermeld4666f52021-01-25 16:27:57 +0000175 zfp->mp = mp;
176 rc = mp->fs->open(zfp, file_name, flags);
Dominik Ermel045900e2020-10-21 13:02:49 +0000177 if (rc < 0) {
178 LOG_ERR("file open error (%d)", rc);
Dominik Ermeld4666f52021-01-25 16:27:57 +0000179 zfp->mp = NULL;
Dominik Ermel045900e2020-10-21 13:02:49 +0000180 return rc;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530181 }
182
Pierrick Guillaume724762f2024-06-17 14:52:17 +0200183 /* Copy flags to zfp for use with other fs_ API calls */
184 zfp->flags = flags;
185
RAJAGOPALAN GANGADHARAN65c4ca12024-05-21 23:42:16 +0530186 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
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530196 return rc;
197}
198
199int fs_close(struct fs_file_t *zfp)
200{
201 int rc = -EINVAL;
202
Dominik Ermel54492c22020-07-03 09:23:34 +0000203 if (zfp->mp == NULL) {
204 return 0;
205 }
206
Dominik Ermel045900e2020-10-21 13:02:49 +0000207 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;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530215 }
216
217 zfp->mp = NULL;
218
219 return rc;
220}
221
222ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size)
223{
224 int rc = -EINVAL;
225
Dominik Ermela5b3e862020-07-03 09:28:36 +0000226 if (zfp->mp == NULL) {
227 return -EBADF;
228 }
229
Dominik Ermel045900e2020-10-21 13:02:49 +0000230 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530237 }
238
239 return rc;
240}
241
242ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size)
243{
244 int rc = -EINVAL;
245
Dominik Ermela5b3e862020-07-03 09:28:36 +0000246 if (zfp->mp == NULL) {
247 return -EBADF;
248 }
249
Dominik Ermel045900e2020-10-21 13:02:49 +0000250 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530257 }
258
259 return rc;
260}
261
262int fs_seek(struct fs_file_t *zfp, off_t offset, int whence)
263{
Dominik Ermeld795f2d2020-10-01 14:19:18 +0000264 int rc = -ENOTSUP;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530265
Dominik Ermela5b3e862020-07-03 09:28:36 +0000266 if (zfp->mp == NULL) {
267 return -EBADF;
268 }
269
Dominik Ermel045900e2020-10-21 13:02:49 +0000270 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530277 }
278
279 return rc;
280}
281
282off_t fs_tell(struct fs_file_t *zfp)
283{
Dominik Ermeld795f2d2020-10-01 14:19:18 +0000284 int rc = -ENOTSUP;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530285
Dominik Ermela5b3e862020-07-03 09:28:36 +0000286 if (zfp->mp == NULL) {
287 return -EBADF;
288 }
289
Dominik Ermel045900e2020-10-21 13:02:49 +0000290 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530297 }
298
299 return rc;
300}
301
302int fs_truncate(struct fs_file_t *zfp, off_t length)
303{
304 int rc = -EINVAL;
305
Dominik Ermela5b3e862020-07-03 09:28:36 +0000306 if (zfp->mp == NULL) {
307 return -EBADF;
308 }
309
Dominik Ermel045900e2020-10-21 13:02:49 +0000310 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530317 }
318
319 return rc;
320}
321
322int fs_sync(struct fs_file_t *zfp)
323{
324 int rc = -EINVAL;
325
Dominik Ermela5b3e862020-07-03 09:28:36 +0000326 if (zfp->mp == NULL) {
327 return -EBADF;
328 }
329
Dominik Ermel045900e2020-10-21 13:02:49 +0000330 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530337 }
338
339 return rc;
340}
341
342/* Directory operations */
343int fs_opendir(struct fs_dir_t *zdp, const char *abs_path)
344{
345 struct fs_mount_t *mp;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530346 int rc = -EINVAL;
347
348 if ((abs_path == NULL) ||
Jim Parisfae62fc2019-07-24 14:15:08 -0400349 (strlen(abs_path) < 1) || (abs_path[0] != '/')) {
Dominik Ermel2cb4d412021-11-08 11:42:23 +0000350 LOG_ERR("invalid directory name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530351 return -EINVAL;
352 }
353
Andrzej Puzdrowski6fb7ac22021-02-03 12:30:45 +0100354 if (zdp->mp != NULL || zdp->dirp != NULL) {
355 return -EBUSY;
356 }
357
358
Jim Parisfae62fc2019-07-24 14:15:08 -0400359 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
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530371 rc = fs_get_mnt_point(&mp, abs_path, NULL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530372 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200373 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530374 return rc;
375 }
376
Dominik Ermel045900e2020-10-21 13:02:49 +0000377 CHECKIF(mp->fs->opendir == NULL) {
378 return -ENOTSUP;
379 }
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530380
Dominik Ermel045900e2020-10-21 13:02:49 +0000381 zdp->mp = mp;
382 rc = zdp->mp->fs->opendir(zdp, abs_path);
383 if (rc < 0) {
Andrzej Puzdrowski6fb7ac22021-02-03 12:30:45 +0100384 zdp->mp = NULL;
385 zdp->dirp = NULL;
Dominik Ermel045900e2020-10-21 13:02:49 +0000386 LOG_ERR("directory open error (%d)", rc);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530387 }
388
389 return rc;
390}
391
392int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry)
393{
Jim Parisfae62fc2019-07-24 14:15:08 -0400394 if (zdp->mp) {
395 /* Delegate to mounted filesystem */
396 int rc = -EINVAL;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530397
Dominik Ermel045900e2020-10-21 13:02:49 +0000398 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);
Jim Parisfae62fc2019-07-24 14:15:08 -0400405 if (rc < 0) {
Dominik Ermel045900e2020-10-21 13:02:49 +0000406 break;
Jim Parisfae62fc2019-07-24 14:15:08 -0400407 }
Dominik Ermel045900e2020-10-21 13:02:49 +0000408 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);
Jim Parisfae62fc2019-07-24 14:15:08 -0400421 }
Peter A. Bigota8b7a212019-08-02 09:50:52 -0500422
Jim Parisfae62fc2019-07-24 14:15:08 -0400423 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;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530457 }
458 }
Jim Parisfae62fc2019-07-24 14:15:08 -0400459
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;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530471}
472
473int fs_closedir(struct fs_dir_t *zdp)
474{
475 int rc = -EINVAL;
476
Jim Parisfae62fc2019-07-24 14:15:08 -0400477 if (zdp->mp == NULL) {
478 /* VFS root dir */
479 zdp->dirp = NULL;
480 return 0;
481 }
482
Dominik Ermel045900e2020-10-21 13:02:49 +0000483 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;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530491 }
492
493 zdp->mp = NULL;
Andrzej Puzdrowski6fb7ac22021-02-03 12:30:45 +0100494 zdp->dirp = NULL;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530495 return rc;
496}
497
498/* Filesystem operations */
499int fs_mkdir(const char *abs_path)
500{
501 struct fs_mount_t *mp;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530502 int rc = -EINVAL;
503
504 if ((abs_path == NULL) ||
505 (strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
Dominik Ermel2cb4d412021-11-08 11:42:23 +0000506 LOG_ERR("invalid directory name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530507 return -EINVAL;
508 }
509
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530510 rc = fs_get_mnt_point(&mp, abs_path, NULL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530511 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200512 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530513 return rc;
514 }
515
Dominik Ermelaa0fd022020-10-08 11:36:57 +0000516 if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
517 return -EROFS;
518 }
519
Dominik Ermel045900e2020-10-21 13:02:49 +0000520 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530527 }
528
529 return rc;
530}
531
532int fs_unlink(const char *abs_path)
533{
534 struct fs_mount_t *mp;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530535 int rc = -EINVAL;
536
537 if ((abs_path == NULL) ||
538 (strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530539 LOG_ERR("invalid file name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530540 return -EINVAL;
541 }
542
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530543 rc = fs_get_mnt_point(&mp, abs_path, NULL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530544 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200545 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530546 return rc;
547 }
548
Dominik Ermelaa0fd022020-10-08 11:36:57 +0000549 if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
550 return -EROFS;
551 }
552
Dominik Ermel045900e2020-10-21 13:02:49 +0000553 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530560 }
561
562 return rc;
563}
564
565int 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] != '/')) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530573 LOG_ERR("invalid file name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530574 return -EINVAL;
575 }
576
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530577 rc = fs_get_mnt_point(&mp, from, &match_len);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530578 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200579 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530580 return rc;
581 }
582
Dominik Ermelaa0fd022020-10-08 11:36:57 +0000583 if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
584 return -EROFS;
585 }
586
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530587 /* Make sure both files are mounted on the same path */
588 if (strncmp(from, to, match_len) != 0) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530589 LOG_ERR("mount point not same!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530590 return -EINVAL;
591 }
592
Dominik Ermel045900e2020-10-21 13:02:49 +0000593 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530600 }
601
602 return rc;
603}
604
605int fs_stat(const char *abs_path, struct fs_dirent *entry)
606{
607 struct fs_mount_t *mp;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530608 int rc = -EINVAL;
609
610 if ((abs_path == NULL) ||
611 (strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
Dominik Ermel2cb4d412021-11-08 11:42:23 +0000612 LOG_ERR("invalid file or dir name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530613 return -EINVAL;
614 }
615
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530616 rc = fs_get_mnt_point(&mp, abs_path, NULL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530617 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200618 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530619 return rc;
620 }
621
Dominik Ermel045900e2020-10-21 13:02:49 +0000622 CHECKIF(mp->fs->stat == NULL) {
623 return -ENOTSUP;
624 }
625
626 rc = mp->fs->stat(mp, abs_path, entry);
Emil Lindqvist1e9f1232021-06-29 10:07:48 +0200627 if (rc == -ENOENT) {
628 /* File doesn't exist, which is a valid stat response */
629 } else if (rc < 0) {
Dominik Ermel045900e2020-10-21 13:02:49 +0000630 LOG_ERR("failed get file or dir stat (%d)", rc);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530631 }
632 return rc;
633}
634
635int fs_statvfs(const char *abs_path, struct fs_statvfs *stat)
636{
637 struct fs_mount_t *mp;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530638 int rc;
639
640 if ((abs_path == NULL) ||
641 (strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
Dominik Ermel2cb4d412021-11-08 11:42:23 +0000642 LOG_ERR("invalid file or dir name!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530643 return -EINVAL;
644 }
645
Ramakrishna Pallaladd5449a2018-04-16 22:14:48 +0530646 rc = fs_get_mnt_point(&mp, abs_path, NULL);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530647 if (rc < 0) {
Fredrik Gihl7e385d72021-05-11 08:13:13 +0200648 LOG_ERR("mount point not found!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530649 return rc;
650 }
651
Dominik Ermele489bb12021-11-08 11:19:40 +0000652 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);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530659 }
660
661 return rc;
662}
663
664int fs_mount(struct fs_mount_t *mp)
665{
666 struct fs_mount_t *itr;
Peter A. Bigot353336d2020-06-01 11:36:52 -0500667 const struct fs_file_system_t *fs;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530668 sys_dnode_t *node;
669 int rc = -EINVAL;
Dominik Ermel5faf3752020-10-15 13:12:41 +0000670 size_t len = 0;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530671
Dominik Ermel5faf3752020-10-15 13:12:41 +0000672 /* Do all the mp checks prior to locking the mutex on the file
673 * subsystem.
674 */
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530675 if ((mp == NULL) || (mp->mnt_point == NULL)) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530676 LOG_ERR("mount point not initialized!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530677 return -EINVAL;
678 }
679
Dominik Ermel6238bf42022-01-07 15:27:46 +0000680 if (sys_dnode_is_linked(&mp->node)) {
681 LOG_ERR("file system already mounted!!");
682 return -EBUSY;
683 }
684
Dominik Ermel5faf3752020-10-15 13:12:41 +0000685 len = strlen(mp->mnt_point);
686
Chris Friedtec7d2722024-12-27 08:44:59 -0500687 if ((len == 0) || (mp->mnt_point[0] != '/')) {
Dominik Ermel5faf3752020-10-15 13:12:41 +0000688 LOG_ERR("invalid mount point!!");
689 return -EINVAL;
690 }
691
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530692 k_mutex_lock(&mutex, K_FOREVER);
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500693
Dominik Ermel5faf3752020-10-15 13:12:41 +0000694 /* 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
Dominik Ermelabb93d42022-01-07 15:46:45 +0000702 CHECKIF(mp->fs_data == itr->fs_data) {
703 LOG_ERR("file system already mounted!!");
704 rc = -EBUSY;
705 goto mount_err;
706 }
707
Dominik Ermel5faf3752020-10-15 13:12:41 +0000708 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
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500715 /* Get file system information */
716 fs = fs_type_get(mp->type);
717 if (fs == NULL) {
718 LOG_ERR("requested file system type not registered!!");
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530719 rc = -ENOENT;
720 goto mount_err;
721 }
722
Dominik Ermel045900e2020-10-21 13:02:49 +0000723 CHECKIF(fs->mount == NULL) {
Dominik Ermel5faf3752020-10-15 13:12:41 +0000724 LOG_ERR("fs type %d does not support mounting", mp->type);
725 rc = -ENOTSUP;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530726 goto mount_err;
727 }
728
Dominik Ermel5faf3752020-10-15 13:12:41 +0000729 if (fs->unmount == NULL) {
730 LOG_WRN("mount path %s is not unmountable",
Krzysztof Chruscinski041f0e52022-06-20 07:43:37 +0200731 mp->mnt_point);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530732 }
733
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530734 rc = fs->mount(mp);
735 if (rc < 0) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530736 LOG_ERR("fs mount error (%d)", rc);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530737 goto mount_err;
738 }
739
Dominik Ermel5faf3752020-10-15 13:12:41 +0000740 /* Update mount point data and append it to the list */
741 mp->mountp_len = len;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530742 mp->fs = fs;
743
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530744 sys_dlist_append(&fs_mnt_list, &mp->node);
Krzysztof Chruscinski041f0e52022-06-20 07:43:37 +0200745 LOG_DBG("fs mounted at %s", mp->mnt_point);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530746
747mount_err:
748 k_mutex_unlock(&mutex);
749 return rc;
750}
751
Franciszek Zdobylak7a96ed22022-10-24 08:36:32 +0200752#if defined(CONFIG_FILE_SYSTEM_MKFS)
753
754int 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
782mount_err:
783 k_mutex_unlock(&mutex);
784 return rc;
785}
786
787#endif /* CONFIG_FILE_SYSTEM_MKFS */
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530788
789int fs_unmount(struct fs_mount_t *mp)
790{
791 int rc = -EINVAL;
792
Dominik Ermele7886c62020-10-15 13:26:59 +0000793 if (mp == NULL) {
794 return rc;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530795 }
796
797 k_mutex_lock(&mutex, K_FOREVER);
Dominik Ermele7886c62020-10-15 13:26:59 +0000798
Dominik Ermel6238bf42022-01-07 15:27:46 +0000799 if (!sys_dnode_is_linked(&mp->node)) {
Dominik Ermele7886c62020-10-15 13:26:59 +0000800 LOG_ERR("fs not mounted (mp == %p)", mp);
801 goto unmount_err;
802 }
803
Dominik Ermel045900e2020-10-21 13:02:49 +0000804 CHECKIF(mp->fs->unmount == NULL) {
805 LOG_ERR("fs unmount not supported!!");
Dominik Ermele7886c62020-10-15 13:26:59 +0000806 rc = -ENOTSUP;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530807 goto unmount_err;
808 }
809
810 rc = mp->fs->unmount(mp);
811 if (rc < 0) {
Varun Sharma7622fc32018-10-12 02:54:24 +0530812 LOG_ERR("fs unmount error (%d)", rc);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530813 goto unmount_err;
814 }
815
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530816 /* remove mount node from the list */
817 sys_dlist_remove(&mp->node);
Krzysztof Chruscinski041f0e52022-06-20 07:43:37 +0200818 LOG_DBG("fs unmounted from %s", mp->mnt_point);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530819
820unmount_err:
821 k_mutex_unlock(&mutex);
822 return rc;
823}
824
Dominik Ermel81dc3472020-09-23 15:04:07 +0000825int fs_readmount(int *index, const char **name)
Jan Van Winkel3815ae62019-01-14 20:45:04 +0100826{
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) {
Dominik Ermel81dc3472020-09-23 15:04:07 +0000837 if (*index == cnt) {
Jan Van Winkel3815ae62019-01-14 20:45:04 +0100838 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;
Dominik Ermel81dc3472020-09-23 15:04:07 +0000850 ++(*index);
Jan Van Winkel3815ae62019-01-14 20:45:04 +0100851 }
852
853 return rc;
854
855}
856
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530857/* Register File system */
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500858int fs_register(int type, const struct fs_file_system_t *fs)
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530859{
860 int rc = 0;
861
862 k_mutex_lock(&mutex, K_FOREVER);
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500863
864 if (fs_type_get(type) != NULL) {
865 rc = -EALREADY;
866 } else {
867 rc = registry_add(type, fs);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530868 }
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500869
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530870 k_mutex_unlock(&mutex);
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500871
872 LOG_DBG("fs register %d: %d", type, rc);
873
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530874 return rc;
875}
876
877/* Unregister File system */
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500878int fs_unregister(int type, const struct fs_file_system_t *fs)
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530879{
880 int rc = 0;
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500881 struct registry_entry *ep;
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530882
883 k_mutex_lock(&mutex, K_FOREVER);
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500884
885 ep = registry_find(type);
886 if ((ep == NULL) || (ep->fstp != fs)) {
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530887 rc = -EINVAL;
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500888 } else {
889 registry_clear_entry(ep);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530890 }
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500891
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530892 k_mutex_unlock(&mutex);
Peter A. Bigotd0d3c4a2020-06-01 12:08:58 -0500893
894 LOG_DBG("fs unregister %d: %d", type, rc);
Ramakrishna Pallala25302b12018-02-22 13:32:57 +0530895 return rc;
896}