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