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