1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  * Copyright (c) 2020-2021 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  *
256  * @details
257  * @p flags can be 0 or a binary combination of one or more of the following
258  * identifiers:
259  *   - @c FS_O_READ open for read
260  *   - @c FS_O_WRITE open for write
261  *   - @c FS_O_RDWR open for read/write (<tt>FS_O_READ | FS_O_WRITE</tt>)
262  *   - @c FS_O_CREATE create file if it does not exist
263  *   - @c FS_O_APPEND move to end of file before each write
264  *
265  * If @p flags are set to 0 the function will attempt to open an existing file
266  * with no read/write access; this may be used to e.g. check if the file exists.
267  *
268  * @param zfp Pointer to a file object
269  * @param file_name The name of a file to open
270  * @param flags The mode flags
271  *
272  * @retval 0 on success;
273  * @retval -EBUSY when zfp is already used;
274  * @retval -EINVAL when a bad file name is given;
275  * @retval -EROFS when opening read-only file for write, or attempting to
276  *	   create a file on a system that has been mounted with the
277  *	   FS_MOUNT_FLAG_READ_ONLY flag;
278  * @retval -ENOENT when the file path is not possible (bad mount point);
279  * @retval -ENOTSUP when not implemented by underlying file system driver;
280  * @retval <0 an other negative errno code, depending on a file system back-end.
281  */
282 int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags);
283 
284 /**
285  * @brief Close file
286  *
287  * Flushes the associated stream and closes the file.
288  *
289  * @param zfp Pointer to the file object
290  *
291  * @retval 0 on success;
292  * @retval -ENOTSUP when not implemented by underlying file system driver;
293  * @retval <0 a negative errno code on error.
294  */
295 int fs_close(struct fs_file_t *zfp);
296 
297 /**
298  * @brief Unlink file
299  *
300  * Deletes the specified file or directory
301  *
302  * @param path Path to the file or directory to delete
303  *
304  * @retval 0 on success;
305  * @retval -EINVAL when a bad file name is given;
306  * @retval -EROFS if file is read-only, or when file system has been mounted
307  *	   with the FS_MOUNT_FLAG_READ_ONLY flag;
308  * @retval -ENOTSUP when not implemented by underlying file system driver;
309  * @retval <0 an other negative errno code on error.
310  */
311 int fs_unlink(const char *path);
312 
313 /**
314  * @brief Rename file or directory
315  *
316  * Performs a rename and / or move of the specified source path to the
317  * specified destination.  The source path can refer to either a file or a
318  * directory.  All intermediate directories in the destination path must
319  * already exist.  If the source path refers to a file, the destination path
320  * must contain a full filename path, rather than just the new parent
321  * directory.  If an object already exists at the specified destination path,
322  * this function causes it to be unlinked prior to the rename (i.e., the
323  * destination gets clobbered).
324  * @note Current implementation does not allow moving files between mount
325  * points.
326  *
327  * @param from The source path
328  * @param to The destination path
329  *
330  * @retval 0 on success;
331  * @retval -EINVAL when a bad file name is given, or when rename would cause move
332  *	   between mount points;
333  * @retval -EROFS if file is read-only, or when file system has been mounted
334  *	   with the FS_MOUNT_FLAG_READ_ONLY flag;
335  * @retval -ENOTSUP when not implemented by underlying file system driver;
336  * @retval <0 an other negative errno code on error.
337  */
338 int fs_rename(const char *from, const char *to);
339 
340 /**
341  * @brief Read file
342  *
343  * Reads up to @p size bytes of data to @p ptr pointed buffer, returns number
344  * of bytes read.  A returned value may be lower than @p size if there were
345  * fewer bytes available than requested.
346  *
347  * @param zfp Pointer to the file object
348  * @param ptr Pointer to the data buffer
349  * @param size Number of bytes to be read
350  *
351  * @retval >=0 a number of bytes read, on success;
352  * @retval -EBADF when invoked on zfp that represents unopened/closed file;
353  * @retval -ENOTSUP when not implemented by underlying file system driver;
354  * @retval <0 a negative errno code on error.
355  */
356 ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size);
357 
358 /**
359  * @brief Write file
360  *
361  * Attempts to write @p size number of bytes to the specified file.
362  * If a negative value is returned from the function, the file pointer has not
363  * been advanced.
364  * If the function returns a non-negative number that is lower than @p size,
365  * the global @c errno variable should be checked for an error code,
366  * as the device may have no free space for data.
367  *
368  * @param zfp Pointer to the file object
369  * @param ptr Pointer to the data buffer
370  * @param size Number of bytes to be written
371  *
372  * @retval >=0 a number of bytes written, on success;
373  * @retval -EBADF when invoked on zfp that represents unopened/closed file;
374  * @retval -ENOTSUP when not implemented by underlying file system driver;
375  * @retval <0 an other negative errno code on error.
376  */
377 ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size);
378 
379 /**
380  * @brief Seek file
381  *
382  * Moves the file position to a new location in the file. The @p offset is added
383  * to file position based on the @p whence parameter.
384  *
385  * @param zfp Pointer to the file object
386  * @param offset Relative location to move the file pointer to
387  * @param whence Relative location from where offset is to be calculated.
388  * - @c FS_SEEK_SET for the beginning of the file;
389  * - @c FS_SEEK_CUR for the current position;
390  * - @c FS_SEEK_END for the end of the file.
391  *
392  * @retval 0 on success;
393  * @retval -EBADF when invoked on zfp that represents unopened/closed file;
394  * @retval -ENOTSUP if not supported by underlying file system driver;
395  * @retval <0 an other negative errno code on error.
396  */
397 int fs_seek(struct fs_file_t *zfp, off_t offset, int whence);
398 
399 /**
400  * @brief Get current file position.
401  *
402  * Retrieves and returns the current position in the file stream.
403  *
404  * @param zfp Pointer to the file object
405  *
406  * @retval >= 0 a current position in file;
407  * @retval -EBADF when invoked on zfp that represents unopened/closed file;
408  * @retval -ENOTSUP if not supported by underlying file system driver;
409  * @retval <0 an other negative errno code on error.
410  *
411  * The current revision does not validate the file object.
412  */
413 off_t fs_tell(struct fs_file_t *zfp);
414 
415 /**
416  * @brief Truncate or extend an open file to a given size
417  *
418  * Truncates the file to the new length if it is shorter than the current
419  * size of the file. Expands the file if the new length is greater than the
420  * current size of the file. The expanded region would be filled with zeroes.
421  *
422  * @note In the case of expansion, if the volume got full during the
423  * expansion process, the function will expand to the maximum possible length
424  * and return success.  Caller should check if the expanded size matches the
425  * requested length.
426  *
427  * @param zfp Pointer to the file object
428  * @param length New size of the file in bytes
429  *
430  * @retval 0 on success;
431  * @retval -EBADF when invoked on zfp that represents unopened/closed file;
432  * @retval -ENOTSUP when not implemented by underlying file system driver;
433  * @retval <0 an other negative errno code on error.
434  */
435 int fs_truncate(struct fs_file_t *zfp, off_t length);
436 
437 /**
438  * @brief Flush cached write data buffers of an open file
439  *
440  * The function flushes the cache of an open file; it can be invoked to ensure
441  * data gets written to the storage media immediately, e.g. to avoid data loss
442  * in case if power is removed unexpectedly.
443  * @note Closing a file will cause caches to be flushed correctly so the
444  * function need not be called when the file is being closed.
445  *
446  * @param zfp Pointer to the file object
447  *
448  * @retval 0 on success;
449  * @retval -EBADF when invoked on zfp that represents unopened/closed file;
450  * @retval -ENOTSUP when not implemented by underlying file system driver;
451  * @retval <0 a negative errno code on error.
452  */
453 int fs_sync(struct fs_file_t *zfp);
454 
455 /**
456  * @brief Directory create
457  *
458  * Creates a new directory using specified path.
459  *
460  * @param path Path to the directory to create
461  *
462  * @retval 0 on success;
463  * @retval -EEXIST if entry of given name exists;
464  * @retval -EROFS if @p path is within read-only directory, or when
465  *         file system has been mounted with the FS_MOUNT_FLAG_READ_ONLY flag;
466  * @retval -ENOTSUP when not implemented by underlying file system driver;
467  * @retval <0 an other negative errno code on error
468  */
469 int fs_mkdir(const char *path);
470 
471 /**
472  * @brief Directory open
473  *
474  * Opens an existing directory specified by the path.
475  *
476  * @param zdp Pointer to the directory object
477  * @param path Path to the directory to open
478  *
479  * @retval 0 on success;
480  * @retval -EINVAL when a bad directory path is given;
481  * @retval -EBUSY when zdp is already used;
482  * @retval -ENOTSUP when not implemented by underlying file system driver;
483  * @retval <0 a negative errno code on error.
484  */
485 int fs_opendir(struct fs_dir_t *zdp, const char *path);
486 
487 /**
488  * @brief Directory read entry
489  *
490  * Reads directory entries of an open directory. In end-of-dir condition,
491  * the function will return 0 and set the <tt>entry->name[0]</tt> to 0.
492  *
493  * @note: Most existing underlying file systems do not generate POSIX
494  * special directory entries "." or "..".  For consistency the
495  * abstraction layer will remove these from lower layer results so
496  * higher layers see consistent results.
497  *
498  * @param zdp Pointer to the directory object
499  * @param entry Pointer to zfs_dirent structure to read the entry into
500  *
501  * @retval 0 on success or end-of-dir;
502  * @retval -ENOENT when no such directory found;
503  * @retval -ENOTSUP when not implemented by underlying file system driver;
504  * @retval <0 a negative errno code on error.
505  */
506 int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry);
507 
508 /**
509  * @brief Directory close
510  *
511  * Closes an open directory.
512  *
513  * @param zdp Pointer to the directory object
514  *
515  * @retval 0 on success;
516  * @retval -ENOTSUP when not implemented by underlying file system driver;
517  * @retval <0 a negative errno code on error.
518  */
519 int fs_closedir(struct fs_dir_t *zdp);
520 
521 /**
522  * @brief Mount filesystem
523  *
524  * Perform steps needed for mounting a file system like
525  * calling the file system specific mount function and adding
526  * the mount point to mounted file system list.
527  *
528  * @note Current implementation of ELM FAT driver allows only following mount
529  * points: "/RAM:","/NAND:","/CF:","/SD:","/SD2:","/USB:","/USB2:","/USB3:"
530  * or mount points that consist of single digit, e.g: "/0:", "/1:" and so forth.
531  *
532  * @param mp Pointer to the fs_mount_t structure.  Referenced object
533  *	     is not changed if the mount operation failed.
534  *	     A reference is captured in the fs infrastructure if the
535  *	     mount operation succeeds, and the application must not
536  *	     mutate the structure contents until fs_unmount is
537  *	     successfully invoked on the same pointer.
538  *
539  * @retval 0 on success;
540  * @retval -ENOENT when file system type has not been registered;
541  * @retval -ENOTSUP when not supported by underlying file system driver;
542  *         when @c FS_MOUNT_FLAG_USE_DISK_ACCESS is set but driver does not
543  *         support it.
544  * @retval -EROFS if system requires formatting but @c FS_MOUNT_FLAG_READ_ONLY
545  *	   has been set;
546  * @retval <0 an other negative errno code on error.
547  */
548 int fs_mount(struct fs_mount_t *mp);
549 
550 /**
551  * @brief Unmount filesystem
552  *
553  * Perform steps needed to unmount a file system like
554  * calling the file system specific unmount function and removing
555  * the mount point from mounted file system list.
556  *
557  * @param mp Pointer to the fs_mount_t structure
558  *
559  * @retval 0 on success;
560  * @retval -EINVAL if no system has been mounted at given mount point;
561  * @retval -ENOTSUP when not supported by underlying file system driver;
562  * @retval <0 an other negative errno code on error.
563  */
564 int fs_unmount(struct fs_mount_t *mp);
565 
566 /**
567  * @brief Get path of mount point at index
568  *
569  * This function iterates through the list of mount points and returns
570  * the directory name of the mount point at the given @p index.
571  * On success @p index is incremented and @p name is set to the mount directory
572  * name.  If a mount point with the given @p index does not exist, @p name will
573  * be set to @c NULL.
574  *
575  * @param index Pointer to mount point index
576  * @param name Pointer to pointer to path name
577  *
578  * @retval 0 on success;
579  * @retval -ENOENT if there is no mount point with given index.
580  */
581 int fs_readmount(int *index, const char **name);
582 
583 /**
584  * @brief File or directory status
585  *
586  * Checks the status of a file or directory specified by the @p path.
587  * @note The file on a storage device may not be updated until it is closed.
588  *
589  * @param path Path to the file or directory
590  * @param entry Pointer to the zfs_dirent structure to fill if the file or
591  * directory exists.
592  *
593  * @retval 0 on success;
594  * @retval -EINVAL when a bad directory or file name is given;
595  * @retval -ENOENT when no such directory or file is found;
596  * @retval -ENOTSUP when not supported by underlying file system driver;
597  * @retval <0 negative errno code on error.
598  */
599 int fs_stat(const char *path, struct fs_dirent *entry);
600 
601 /**
602  * @brief Retrieves statistics of the file system volume
603  *
604  * Returns the total and available space in the file system volume.
605  *
606  * @param path Path to the mounted directory
607  * @param stat Pointer to the zfs_statvfs structure to receive the fs
608  * statistics.
609  *
610  * @retval 0 on success;
611  * @retval -EINVAL when a bad path to a directory, or a file, is given;
612  * @retval -ENOTSUP when not implemented by underlying file system driver;
613  * @retval <0 an other negative errno code on error.
614  */
615 int fs_statvfs(const char *path, struct fs_statvfs *stat);
616 
617 /**
618  * @brief Create fresh file system
619  *
620  * @param fs_type Type of file system to create.
621  * @param dev_id Id of storage device.
622  * @param cfg Backend dependent init object. If NULL then default configuration is used.
623  * @param flags Additional flags for file system implementation.
624  *
625  * @retval 0 on success;
626  * @retval <0 negative errno code on error.
627  */
628 int fs_mkfs(int fs_type, uintptr_t dev_id, void *cfg, int flags);
629 
630 /**
631  * @brief Register a file system
632  *
633  * Register file system with virtual file system.
634  * Number of allowed file system types to be registered is controlled with the
635  * CONFIG_FILE_SYSTEM_MAX_TYPES Kconfig option.
636  *
637  * @param type Type of file system (ex: @c FS_FATFS)
638  * @param fs Pointer to File system
639  *
640  * @retval 0 on success;
641  * @retval -EALREADY when a file system of a given type has already been registered;
642  * @retval -ENOSCP when there is no space left, in file system registry, to add
643  *	   this file system type.
644  */
645 int fs_register(int type, const struct fs_file_system_t *fs);
646 
647 /**
648  * @brief Unregister a file system
649  *
650  * Unregister file system from virtual file system.
651  *
652  * @param type Type of file system (ex: @c FS_FATFS)
653  * @param fs Pointer to File system
654  *
655  * @retval 0 on success;
656  * @retval -EINVAL when file system of a given type has not been registered.
657  */
658 int fs_unregister(int type, const struct fs_file_system_t *fs);
659 
660 /**
661  * @}
662  */
663 
664 
665 #ifdef __cplusplus
666 }
667 #endif
668 
669 #endif /* ZEPHYR_INCLUDE_FS_FS_H_ */
670