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