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