File System Abstraction

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.

Description

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.

Support for multiple filesystems

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.

struct disk_ops

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;
}

Thread Safety

All fs/fs functions are thread safe.

Header Files

All code which uses the fs/fs package needs to include the following header:

#include "fs/fs.h"

Data Structures

All fs/fs data structures are opaque to client code.

struct fs_file;
struct fs_dir;
struct fs_dirent;

API

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:

FunctionDescription
fs_closeCloses the specified file and invalidates the file handle.
fs_closedirCloses the specified directory handle.
fs_dirent_is_dirTells you whether the specified directory entry is a sub-directory or a regular file.
fs_dirent_nameRetrieves the filename of the specified directory entry.
fs_filelenRetrieves the current length of the specified open file.
fs_getposRetrieves the current read and write position of the specified open file.
fs_mkdirCreates the directory represented by the specified path.
fs_openOpens a file at the specified path.
fs_opendirOpens the directory at the specified path.
fs_readReads data from the specified file.
fs_readdirReads the next entry in an open directory.
fs_registerRegisters a file system with the abstraction layer.
fs_renamePerforms a rename and/or move of the specified source path to the specified destination.
fs_seekPositions a file's read and write pointer at the specified offset.
fs_unlinkUnlinks the file or directory at the specified path.
fs_writeWrites 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:

FunctionDescription
fsutil_read_fileOpens 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_fileOpen 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.