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