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