Mynewt provides a file system abstraction layer (fs/fs
) to allow client code to be file system agnostic. By accessing the file system via the fs/fs
API, client code can perform file system operations without being tied to a particular implementation. When possible, library code should use the fs/fs
API rather than accessing the underlying file system directly.
Applications should aim to minimize the amount of code which depends on a particular file system implementation. When possible, only depend on the fs/fs
package. In terms of the Mynewt hierarchy, an app package must depend on a specific file system package, while library packages should only depend on fs/fs
.
Applications wanting to access a filesystem are required to include the necessary packages in their applications pkg.yml file. In the following example, the Newtron Flash File System
is used.
# repos/apache-mynewt-core/apps/slinky/pkg.yml pkg.name: repos/apache-mynewt-core/apps/slinky pkg.deps: - fs/fs # include the file operations interfaces - fs/nffs # include the NFFS filesystem implementation
# repos/apache-mynewt-core/apps/slinky/syscfg.yml # [...] # Package: apps/<example app> # [...] CONFIG_NFFS: 1 # initialize and configure NFFS into the system # NFFS_DETECT_FAIL: 1 # Ignore NFFS detection issues # NFFS_DETECT_FAIL: 2 # Format a new NFFS file system on failure to detect # [...]
Consult the documentation for nffs
for a more detailed explanation of NFFS_DETECT_FAIL
Code which uses the file system after the system has been initialized need only depend on fs/fs
. For example, the libs/imgmgr
package is a library which provides firmware upload and download functionality via the use of a file system. This library is only used after the system has been initialized, and therefore only depends on the fs/fs
package.
# repos/apache-mynewt-core/libs/imgmgr/pkg.yml pkg.name: libs/imgmgr pkg.deps: - fs/fs # [...]
The libs/imgmgr
package uses the fs/fs
API for all file system operations.
When using a single filesystem/disk, it is valid to provide paths in the standard unix way, eg, /<dir-name>/<file-name>
. When trying to run more than one filesystem or a single filesystem in multiple devices simultaneosly, an extra name has to be given to the disk that is being used. The abstraction for that was added as the fs/disk
package which is a dependency of fs/fs
. It adds the following extra user function:
int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops)
As an example os usage:
disk_register("mmc0", "fatfs", &mmc_ops); disk_register("flash0", "nffs", NULL);
This registers the name mmc0
to use fatfs
as the filesystem and mmc_ops
for the low-level disk driver and also registers flash0
to use nffs
. nffs
is currently strongly bound to the hal_flash
interface, ignoring any other possible disk_ops
given.
To support a new low-level disk interface, the struct disk_ops
interface must be implemented by the low-level driver. Currently only read
and write
are effectively used (by fatfs
).
struct disk_ops { int (*read)(uint8_t, uint32_t, void *, uint32_t); int (*write)(uint8_t, uint32_t, const void *, uint32_t); int (*ioctl)(uint8_t, uint32_t, void *); SLIST_ENTRY(disk_ops) sc_next; }
All fs/fs
functions are thread safe.
All code which uses the fs/fs
package needs to include the following header:
#include "fs/fs.h"
All fs/fs
data structures are opaque to client code.
struct fs_file; struct fs_dir; struct fs_dirent;
Functions in fs/fs
that indicate success or failure do so with the following set of return codes:
The functions available in this OS feature are:
Function | Description |
---|---|
fs_close | Closes the specified file and invalidates the file handle. |
fs_closedir | Closes the specified directory handle. |
fs_dirent_is_dir | Tells you whether the specified directory entry is a sub-directory or a regular file. |
fs_dirent_name | Retrieves the filename of the specified directory entry. |
fs_filelen | Retrieves the current length of the specified open file. |
fs_getpos | Retrieves the current read and write position of the specified open file. |
fs_mkdir | Creates the directory represented by the specified path. |
fs_open | Opens a file at the specified path. |
fs_opendir | Opens the directory at the specified path. |
fs_read | Reads data from the specified file. |
fs_readdir | Reads the next entry in an open directory. |
fs_register | Registers a file system with the abstraction layer. |
fs_rename | Performs a rename and/or move of the specified source path to the specified destination. |
fs_seek | Positions a file's read and write pointer at the specified offset. |
fs_unlink | Unlinks the file or directory at the specified path. |
fs_write | Writes the supplied data to the current offset of the specified file handle. |
Additional file system utilities that bundle some of the basic functions above are:
Function | Description |
---|---|
fsutil_read_file | Opens a file at the specified path, retrieve data from the file starting from the specified offset, and close the file and invalidate the file handle. |
fsutil_write_file | Open a file at the specified path, write the supplied data to the current offset of the specified file handle, and close the file and invalidate the file handle. |