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