1 /*
2 * Copyright (c) 2016 Intel Corporation.
3 * Copyright (c) 2020-2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #ifndef ZEPHYR_INCLUDE_FS_FS_H_
9 #define ZEPHYR_INCLUDE_FS_FS_H_
10
11 #include <sys/types.h>
12
13 #include <zephyr/sys/dlist.h>
14 #include <zephyr/fs/fs_interface.h>
15
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19
20 /**
21 * @brief File System APIs
22 * @defgroup file_system_api File System APIs
23 * @since 1.5
24 * @version 1.0.0
25 * @ingroup os_services
26 * @{
27 */
28 struct fs_file_system_t;
29
30 /**
31 * @brief Enumeration for directory entry types
32 */
33 enum fs_dir_entry_type {
34 /** Identifier for file entry */
35 FS_DIR_ENTRY_FILE = 0,
36 /** Identifier for directory entry */
37 FS_DIR_ENTRY_DIR
38 };
39
40 /** @brief Enumeration to uniquely identify file system types.
41 *
42 * Zephyr supports in-tree file systems and external ones. Each
43 * requires a unique identifier used to register the file system
44 * implementation and to associate a mount point with the file system
45 * type. This anonymous enum defines global identifiers for the
46 * in-tree file systems.
47 *
48 * External file systems should be registered using unique identifiers
49 * starting at @c FS_TYPE_EXTERNAL_BASE. It is the responsibility of
50 * applications that use external file systems to ensure that these
51 * identifiers are unique if multiple file system implementations are
52 * used by the application.
53 */
54 enum {
55 /** Identifier for in-tree FatFS file system. */
56 FS_FATFS = 0,
57
58 /** Identifier for in-tree LittleFS file system. */
59 FS_LITTLEFS,
60
61 /** Identifier for in-tree Ext2 file system. */
62 FS_EXT2,
63
64 /** Base identifier for external file systems. */
65 FS_TYPE_EXTERNAL_BASE,
66 };
67
68 /** Flag prevents formatting device if requested file system not found */
69 #define FS_MOUNT_FLAG_NO_FORMAT BIT(0)
70 /** Flag makes mounted file system read-only */
71 #define FS_MOUNT_FLAG_READ_ONLY BIT(1)
72 /** Flag used in pre-defined mount structures that are to be mounted
73 * on startup.
74 *
75 * This flag has no impact in user-defined mount structures.
76 */
77 #define FS_MOUNT_FLAG_AUTOMOUNT BIT(2)
78 /** Flag requests file system driver to use Disk Access API. When the flag is
79 * set to the fs_mount_t.flags prior to fs_mount call, a file system
80 * needs to use the Disk Access API, otherwise mount callback for the driver
81 * should return -ENOSUP; when the flag is not set the file system driver
82 * should use Flash API by default, unless it only supports Disc Access API.
83 * When file system will use Disk Access API and the flag is not set, the mount
84 * callback for the file system should set the flag on success.
85 */
86 #define FS_MOUNT_FLAG_USE_DISK_ACCESS BIT(3)
87
88 /**
89 * @brief File system mount info structure
90 */
91 struct fs_mount_t {
92 /** Entry for the fs_mount_list list */
93 sys_dnode_t node;
94 /** File system type */
95 int type;
96 /** Mount point directory name (ex: "/fatfs") */
97 const char *mnt_point;
98 /** Pointer to file system specific data */
99 void *fs_data;
100 /** Pointer to backend storage device */
101 void *storage_dev;
102 /* The following fields are filled by file system core */
103 /** Length of Mount point string */
104 size_t mountp_len;
105 /** Pointer to File system interface of the mount point */
106 const struct fs_file_system_t *fs;
107 /** Mount flags */
108 uint8_t flags;
109 };
110
111 /**
112 * @brief Structure to receive file or directory information
113 *
114 * Used in functions that read the directory entries to get
115 * file or directory information.
116 */
117 struct fs_dirent {
118 /**
119 * File/directory type (FS_DIR_ENTRY_FILE or FS_DIR_ENTRY_DIR)
120 */
121 enum fs_dir_entry_type type;
122 /** Name of file or directory */
123 char name[MAX_FILE_NAME + 1];
124 /** Size of file (0 if directory). */
125 size_t size;
126 };
127
128 /**
129 * @brief Structure to receive volume statistics
130 *
131 * Used to retrieve information about total and available space
132 * in the volume.
133 */
134 struct fs_statvfs {
135 /** Optimal transfer block size */
136 unsigned long f_bsize;
137 /** Allocation unit size */
138 unsigned long f_frsize;
139 /** Size of FS in f_frsize units */
140 unsigned long f_blocks;
141 /** Number of free blocks */
142 unsigned long f_bfree;
143 };
144
145
146 /**
147 * @name fs_open open and creation mode flags
148 * @{
149 */
150 /** Open for read flag */
151 #define FS_O_READ 0x01
152 /** Open for write flag */
153 #define FS_O_WRITE 0x02
154 /** Open for read-write flag combination */
155 #define FS_O_RDWR (FS_O_READ | FS_O_WRITE)
156 /** Bitmask for read and write flags */
157 #define FS_O_MODE_MASK 0x03
158
159 /** Create file if it does not exist */
160 #define FS_O_CREATE 0x10
161 /** Open/create file for append */
162 #define FS_O_APPEND 0x20
163 /** Truncate the file while opening */
164 #define FS_O_TRUNC 0x40
165 /** Bitmask for open/create flags */
166 #define FS_O_FLAGS_MASK 0x70
167
168
169 /** Bitmask for open flags */
170 #define FS_O_MASK (FS_O_MODE_MASK | FS_O_FLAGS_MASK)
171 /**
172 * @}
173 */
174
175 /**
176 * @name fs_seek whence parameter values
177 * @{
178 */
179 #ifndef FS_SEEK_SET
180 /** Seek from the beginning of file */
181 #define FS_SEEK_SET 0
182 #endif
183 #ifndef FS_SEEK_CUR
184 /** Seek from a current position */
185 #define FS_SEEK_CUR 1
186 #endif
187 #ifndef FS_SEEK_END
188 /** Seek from the end of file */
189 #define FS_SEEK_END 2
190 #endif
191 /**
192 * @}
193 */
194
195 /**
196 * @brief Get the common mount flags for an fstab entry.
197
198 * @param node_id the node identifier for a child entry in a
199 * zephyr,fstab node.
200 * @return a value suitable for initializing an fs_mount_t flags
201 * member.
202 */
203 #define FSTAB_ENTRY_DT_MOUNT_FLAGS(node_id) \
204 ((DT_PROP(node_id, automount) ? FS_MOUNT_FLAG_AUTOMOUNT : 0) \
205 | (DT_PROP(node_id, read_only) ? FS_MOUNT_FLAG_READ_ONLY : 0) \
206 | (DT_PROP(node_id, no_format) ? FS_MOUNT_FLAG_NO_FORMAT : 0) \
207 | (DT_PROP(node_id, disk_access) ? FS_MOUNT_FLAG_USE_DISK_ACCESS : 0))
208
209 /**
210 * @brief The name under which a zephyr,fstab entry mount structure is
211 * defined.
212 *
213 * @param node_id the node identifier for a child entry in a zephyr,fstab node.
214 */
215 #define FS_FSTAB_ENTRY(node_id) _CONCAT(z_fsmp_, node_id)
216
217 /**
218 * @brief Generate a declaration for the externally defined fstab
219 * entry.
220 *
221 * This will evaluate to the name of a struct fs_mount_t object.
222 *
223 * @param node_id the node identifier for a child entry in a zephyr,fstab node.
224 */
225 #define FS_FSTAB_DECLARE_ENTRY(node_id) \
226 extern struct fs_mount_t FS_FSTAB_ENTRY(node_id)
227
228 /**
229 * @brief Initialize fs_file_t object
230 *
231 * Initializes the fs_file_t object; the function needs to be invoked
232 * on object before first use with fs_open.
233 *
234 * @param zfp Pointer to file object
235 *
236 */
fs_file_t_init(struct fs_file_t * zfp)237 static inline void fs_file_t_init(struct fs_file_t *zfp)
238 {
239 zfp->filep = NULL;
240 zfp->mp = NULL;
241 zfp->flags = 0;
242 }
243
244 /**
245 * @brief Initialize fs_dir_t object
246 *
247 * Initializes the fs_dir_t object; the function needs to be invoked
248 * on object before first use with fs_opendir.
249 *
250 * @param zdp Pointer to file object
251 *
252 */
fs_dir_t_init(struct fs_dir_t * zdp)253 static inline void fs_dir_t_init(struct fs_dir_t *zdp)
254 {
255 zdp->dirp = NULL;
256 zdp->mp = NULL;
257 }
258
259 /**
260 * @brief Open or create file
261 *
262 * Opens or possibly creates a file and associates a stream with it.
263 * Successfully opened file, when no longer in use, should be closed
264 * with fs_close().
265 *
266 * @details
267 * @p flags can be 0 or a binary combination of one or more of the following
268 * identifiers:
269 * - @c FS_O_READ open for read
270 * - @c FS_O_WRITE open for write
271 * - @c FS_O_RDWR open for read/write (<tt>FS_O_READ | FS_O_WRITE</tt>)
272 * - @c FS_O_CREATE create file if it does not exist
273 * - @c FS_O_APPEND move to end of file before each write
274 * - @c FS_O_TRUNC truncate the file
275 *
276 * @warning If @p flags are set to 0 the function will open file, if it exists
277 * and is accessible, but you will have no read/write access to it.
278 *
279 * @param zfp Pointer to a file object
280 * @param file_name The name of a file to open
281 * @param flags The mode flags
282 *
283 * @retval 0 on success;
284 * @retval -EBUSY when zfp is already used;
285 * @retval -EINVAL when a bad file name is given;
286 * @retval -EROFS when opening read-only file for write, or attempting to
287 * create a file on a system that has been mounted with the
288 * FS_MOUNT_FLAG_READ_ONLY flag;
289 * @retval -ENOENT when the file does not exist at the path;
290 * @retval -ENOTSUP when not implemented by underlying file system driver;
291 * @retval -EACCES when trying to truncate a file without opening it for write.
292 * @retval <0 an other negative errno code, depending on a file system back-end.
293 */
294 int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags);
295
296 /**
297 * @brief Close file
298 *
299 * Flushes the associated stream and closes the file.
300 *
301 * @param zfp Pointer to the file object
302 *
303 * @retval 0 on success;
304 * @retval -ENOTSUP when not implemented by underlying file system driver;
305 * @retval <0 a negative errno code on error.
306 */
307 int fs_close(struct fs_file_t *zfp);
308
309 /**
310 * @brief Unlink file
311 *
312 * Deletes the specified file or directory
313 *
314 * @param path Path to the file or directory to delete
315 *
316 * @retval 0 on success;
317 * @retval -EINVAL when a bad file name is given;
318 * @retval -EROFS if file is read-only, or when file system has been mounted
319 * with the FS_MOUNT_FLAG_READ_ONLY flag;
320 * @retval -ENOTSUP when not implemented by underlying file system driver;
321 * @retval <0 an other negative errno code on error.
322 */
323 int fs_unlink(const char *path);
324
325 /**
326 * @brief Rename file or directory
327 *
328 * Performs a rename and / or move of the specified source path to the
329 * specified destination. The source path can refer to either a file or a
330 * directory. All intermediate directories in the destination path must
331 * already exist. If the source path refers to a file, the destination path
332 * must contain a full filename path, rather than just the new parent
333 * directory. If an object already exists at the specified destination path,
334 * this function causes it to be unlinked prior to the rename (i.e., the
335 * destination gets clobbered).
336 * @note Current implementation does not allow moving files between mount
337 * points.
338 *
339 * @param from The source path
340 * @param to The destination path
341 *
342 * @retval 0 on success;
343 * @retval -EINVAL when a bad file name is given, or when rename would cause move
344 * between mount points;
345 * @retval -EROFS if file is read-only, or when file system has been mounted
346 * with the FS_MOUNT_FLAG_READ_ONLY flag;
347 * @retval -ENOTSUP when not implemented by underlying file system driver;
348 * @retval <0 an other negative errno code on error.
349 */
350 int fs_rename(const char *from, const char *to);
351
352 /**
353 * @brief Read file
354 *
355 * Reads up to @p size bytes of data to @p ptr pointed buffer, returns number
356 * of bytes read. A returned value may be lower than @p size if there were
357 * fewer bytes available than requested.
358 *
359 * @param zfp Pointer to the file object
360 * @param ptr Pointer to the data buffer
361 * @param size Number of bytes to be read
362 *
363 * @retval >=0 a number of bytes read, on success;
364 * @retval -EBADF when invoked on zfp that represents unopened/closed file;
365 * @retval -ENOTSUP when not implemented by underlying file system driver;
366 * @retval <0 a negative errno code on error.
367 */
368 ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size);
369
370 /**
371 * @brief Write file
372 *
373 * Attempts to write @p size number of bytes to the specified file.
374 * If a negative value is returned from the function, the file pointer has not
375 * been advanced.
376 * If the function returns a non-negative number that is lower than @p size,
377 * the global @c errno variable should be checked for an error code,
378 * as the device may have no free space for data.
379 *
380 * @param zfp Pointer to the file object
381 * @param ptr Pointer to the data buffer
382 * @param size Number of bytes to be written
383 *
384 * @retval >=0 a number of bytes written, on success;
385 * @retval -EBADF when invoked on zfp that represents unopened/closed file;
386 * @retval -ENOTSUP when not implemented by underlying file system driver;
387 * @retval <0 an other negative errno code on error.
388 */
389 ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size);
390
391 /**
392 * @brief Seek file
393 *
394 * Moves the file position to a new location in the file. The @p offset is added
395 * to file position based on the @p whence parameter.
396 *
397 * @param zfp Pointer to the file object
398 * @param offset Relative location to move the file pointer to
399 * @param whence Relative location from where offset is to be calculated.
400 * - @c FS_SEEK_SET for the beginning of the file;
401 * - @c FS_SEEK_CUR for the current position;
402 * - @c FS_SEEK_END for the end of the file.
403 *
404 * @retval 0 on success;
405 * @retval -EBADF when invoked on zfp that represents unopened/closed file;
406 * @retval -ENOTSUP if not supported by underlying file system driver;
407 * @retval <0 an other negative errno code on error.
408 */
409 int fs_seek(struct fs_file_t *zfp, off_t offset, int whence);
410
411 /**
412 * @brief Get current file position.
413 *
414 * Retrieves and returns the current position in the file stream.
415 *
416 * @param zfp Pointer to the file object
417 *
418 * @retval >= 0 a current position in file;
419 * @retval -EBADF when invoked on zfp that represents unopened/closed file;
420 * @retval -ENOTSUP if not supported by underlying file system driver;
421 * @retval <0 an other negative errno code on error.
422 *
423 * The current revision does not validate the file object.
424 */
425 off_t fs_tell(struct fs_file_t *zfp);
426
427 /**
428 * @brief Truncate or extend an open file to a given size
429 *
430 * Truncates the file to the new length if it is shorter than the current
431 * size of the file. Expands the file if the new length is greater than the
432 * current size of the file. The expanded region would be filled with zeroes.
433 *
434 * @note In the case of expansion, if the volume got full during the
435 * expansion process, the function will expand to the maximum possible length
436 * and return success. Caller should check if the expanded size matches the
437 * requested length.
438 *
439 * @param zfp Pointer to the file object
440 * @param length New size of the file in bytes
441 *
442 * @retval 0 on success;
443 * @retval -EBADF when invoked on zfp that represents unopened/closed file;
444 * @retval -ENOTSUP when not implemented by underlying file system driver;
445 * @retval <0 an other negative errno code on error.
446 */
447 int fs_truncate(struct fs_file_t *zfp, off_t length);
448
449 /**
450 * @brief Flush cached write data buffers of an open file
451 *
452 * The function flushes the cache of an open file; it can be invoked to ensure
453 * data gets written to the storage media immediately, e.g. to avoid data loss
454 * in case if power is removed unexpectedly.
455 * @note Closing a file will cause caches to be flushed correctly so the
456 * function need not be called when the file is being closed.
457 *
458 * @param zfp Pointer to the file object
459 *
460 * @retval 0 on success;
461 * @retval -EBADF when invoked on zfp that represents unopened/closed file;
462 * @retval -ENOTSUP when not implemented by underlying file system driver;
463 * @retval <0 a negative errno code on error.
464 */
465 int fs_sync(struct fs_file_t *zfp);
466
467 /**
468 * @brief Directory create
469 *
470 * Creates a new directory using specified path.
471 *
472 * @param path Path to the directory to create
473 *
474 * @retval 0 on success;
475 * @retval -EEXIST if entry of given name exists;
476 * @retval -EROFS if @p path is within read-only directory, or when
477 * file system has been mounted with the FS_MOUNT_FLAG_READ_ONLY flag;
478 * @retval -ENOTSUP when not implemented by underlying file system driver;
479 * @retval <0 an other negative errno code on error
480 */
481 int fs_mkdir(const char *path);
482
483 /**
484 * @brief Directory open
485 *
486 * Opens an existing directory specified by the path.
487 *
488 * @param zdp Pointer to the directory object
489 * @param path Path to the directory to open
490 *
491 * @retval 0 on success;
492 * @retval -EINVAL when a bad directory path is given;
493 * @retval -EBUSY when zdp is already used;
494 * @retval -ENOTSUP when not implemented by underlying file system driver;
495 * @retval <0 a negative errno code on error.
496 */
497 int fs_opendir(struct fs_dir_t *zdp, const char *path);
498
499 /**
500 * @brief Directory read entry
501 *
502 * Reads directory entries of an open directory. In end-of-dir condition,
503 * the function will return 0 and set the <tt>entry->name[0]</tt> to 0.
504 *
505 * @note: Most existing underlying file systems do not generate POSIX
506 * special directory entries "." or "..". For consistency the
507 * abstraction layer will remove these from lower layer results so
508 * higher layers see consistent results.
509 *
510 * @param zdp Pointer to the directory object
511 * @param entry Pointer to zfs_dirent structure to read the entry into
512 *
513 * @retval 0 on success or end-of-dir;
514 * @retval -ENOENT when no such directory found;
515 * @retval -ENOTSUP when not implemented by underlying file system driver;
516 * @retval <0 a negative errno code on error.
517 */
518 int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry);
519
520 /**
521 * @brief Directory close
522 *
523 * Closes an open directory.
524 *
525 * @param zdp Pointer to the directory object
526 *
527 * @retval 0 on success;
528 * @retval -ENOTSUP when not implemented by underlying file system driver;
529 * @retval <0 a negative errno code on error.
530 */
531 int fs_closedir(struct fs_dir_t *zdp);
532
533 /**
534 * @brief Mount filesystem
535 *
536 * Perform steps needed for mounting a file system like
537 * calling the file system specific mount function and adding
538 * the mount point to mounted file system list.
539 *
540 * @note Current implementation of ELM FAT driver allows only following mount
541 * points: "/RAM:","/NAND:","/CF:","/SD:","/SD2:","/USB:","/USB2:","/USB3:"
542 * or mount points that consist of single digit, e.g: "/0:", "/1:" and so forth.
543 *
544 * @param mp Pointer to the fs_mount_t structure. Referenced object
545 * is not changed if the mount operation failed.
546 * A reference is captured in the fs infrastructure if the
547 * mount operation succeeds, and the application must not
548 * mutate the structure contents until fs_unmount is
549 * successfully invoked on the same pointer.
550 *
551 * @retval 0 on success;
552 * @retval -ENOENT when file system type has not been registered;
553 * @retval -ENOTSUP when not supported by underlying file system driver;
554 * when @c FS_MOUNT_FLAG_USE_DISK_ACCESS is set but driver does not
555 * support it.
556 * @retval -EROFS if system requires formatting but @c FS_MOUNT_FLAG_READ_ONLY
557 * has been set;
558 * @retval <0 an other negative errno code on error.
559 */
560 int fs_mount(struct fs_mount_t *mp);
561
562 /**
563 * @brief Unmount filesystem
564 *
565 * Perform steps needed to unmount a file system like
566 * calling the file system specific unmount function and removing
567 * the mount point from mounted file system list.
568 *
569 * @param mp Pointer to the fs_mount_t structure
570 *
571 * @retval 0 on success;
572 * @retval -EINVAL if no system has been mounted at given mount point;
573 * @retval -ENOTSUP when not supported by underlying file system driver;
574 * @retval <0 an other negative errno code on error.
575 */
576 int fs_unmount(struct fs_mount_t *mp);
577
578 /**
579 * @brief Get path of mount point at index
580 *
581 * This function iterates through the list of mount points and returns
582 * the directory name of the mount point at the given @p index.
583 * On success @p index is incremented and @p name is set to the mount directory
584 * name. If a mount point with the given @p index does not exist, @p name will
585 * be set to @c NULL.
586 *
587 * @param index Pointer to mount point index
588 * @param name Pointer to pointer to path name
589 *
590 * @retval 0 on success;
591 * @retval -ENOENT if there is no mount point with given index.
592 */
593 int fs_readmount(int *index, const char **name);
594
595 /**
596 * @brief File or directory status
597 *
598 * Checks the status of a file or directory specified by the @p path.
599 * @note The file on a storage device may not be updated until it is closed.
600 *
601 * @param path Path to the file or directory
602 * @param entry Pointer to the zfs_dirent structure to fill if the file or
603 * directory exists.
604 *
605 * @retval 0 on success;
606 * @retval -EINVAL when a bad directory or file name is given;
607 * @retval -ENOENT when no such directory or file is found;
608 * @retval -ENOTSUP when not supported by underlying file system driver;
609 * @retval <0 negative errno code on error.
610 */
611 int fs_stat(const char *path, struct fs_dirent *entry);
612
613 /**
614 * @brief Retrieves statistics of the file system volume
615 *
616 * Returns the total and available space in the file system volume.
617 *
618 * @param path Path to the mounted directory
619 * @param stat Pointer to the zfs_statvfs structure to receive the fs
620 * statistics.
621 *
622 * @retval 0 on success;
623 * @retval -EINVAL when a bad path to a directory, or a file, is given;
624 * @retval -ENOTSUP when not implemented by underlying file system driver;
625 * @retval <0 an other negative errno code on error.
626 */
627 int fs_statvfs(const char *path, struct fs_statvfs *stat);
628
629 /**
630 * @brief Create fresh file system
631 *
632 * @param fs_type Type of file system to create.
633 * @param dev_id Id of storage device.
634 * @param cfg Backend dependent init object. If NULL then default configuration is used.
635 * @param flags Additional flags for file system implementation.
636 *
637 * @retval 0 on success;
638 * @retval <0 negative errno code on error.
639 */
640 int fs_mkfs(int fs_type, uintptr_t dev_id, void *cfg, int flags);
641
642 /**
643 * @brief Register a file system
644 *
645 * Register file system with virtual file system.
646 * Number of allowed file system types to be registered is controlled with the
647 * CONFIG_FILE_SYSTEM_MAX_TYPES Kconfig option.
648 *
649 * @param type Type of file system (ex: @c FS_FATFS)
650 * @param fs Pointer to File system
651 *
652 * @retval 0 on success;
653 * @retval -EALREADY when a file system of a given type has already been registered;
654 * @retval -ENOSCP when there is no space left, in file system registry, to add
655 * this file system type.
656 */
657 int fs_register(int type, const struct fs_file_system_t *fs);
658
659 /**
660 * @brief Unregister a file system
661 *
662 * Unregister file system from virtual file system.
663 *
664 * @param type Type of file system (ex: @c FS_FATFS)
665 * @param fs Pointer to File system
666 *
667 * @retval 0 on success;
668 * @retval -EINVAL when file system of a given type has not been registered.
669 */
670 int fs_unregister(int type, const struct fs_file_system_t *fs);
671
672 /**
673 * @}
674 */
675
676
677 #ifdef __cplusplus
678 }
679 #endif
680
681 #endif /* ZEPHYR_INCLUDE_FS_FS_H_ */
682