Virtual File System (VFS) layer

Provides an interface for accessing files and directories from different devices and file systems. More...

Detailed Description

Provides an interface for accessing files and directories from different devices and file systems.

This layer is modeled as a mix between POSIX syscalls (e.g. open) and the Linux VFS layer implementation, with major reductions in the feature set, in order to fit the resource constrained platforms that RIOT targets.

The overall design goals are:

The API should be easy to understand for users who are familiar with the POSIX file functions (open, close, read, write, fstat, lseek etc.)

The VFS layer keeps track of mounted file systems and open files, the vfs_open function searches the array of mounted file systems and dispatches the call to the file system instance with the longest matching mount point prefix. Subsequent calls to vfs_read, vfs_write, etc will do a look up in the table of open files and dispatch the call to the correct file system driver for handling.

vfs_mount takes a string containing the mount point, a file system driver specification (struct file_system), and an opaque pointer that only the FS driver knows how to use, which can be used to keep driver parameters in order to allow dynamic handling of multiple devices.

Todo:
VFS layer reference counting and locking for open files and simultaneous access.

Modules

 VFS helper functions
 

Files

file  vfs.h
 VFS layer API declarations.
 
file  vfs_default.h
 VFS default mount points.
 

Data Structures

struct  vfs_file_system_t
 A file system driver. More...
 
struct  vfs_mount_struct
 A mounted file system. More...
 
struct  vfs_file_t
 Information about an open file. More...
 
struct  vfs_DIR
 Internal representation of a file system directory entry. More...
 
struct  vfs_dirent_t
 User facing directory entry. More...
 
struct  vfs_file_ops
 Operations on open files. More...
 
struct  vfs_dir_ops
 Operations on open directories. More...
 
struct  vfs_file_system_ops
 Operations on mounted file systems. More...
 

Macros

#define VFS_MAX_OPEN_FILES   (16)
 Maximum number of simultaneous open files.
 
#define VFS_DIR_BUFFER_SIZE
 Size of buffer space in vfs_DIR. More...
 
#define VFS_FILE_BUFFER_SIZE
 Size of buffer space in vfs_file_t. More...
 
#define VFS_NAME_MAX   (31)
 Maximum length of the name in a vfs_dirent_t (not including terminating null) More...
 
#define VFS_ANY_FD   (-1)
 Used with vfs_bind to bind to any available fd number.
 
#define VFS_MTD(mtd)   { .dev = &mtd.base }
 Helper macro for VFS_AUTO_MOUNT. More...
 
#define VFS_AUTO_MOUNT(type, mtd, path, idx)
 Define an automatic mountpoint. More...
 

Typedefs

typedef struct vfs_file_ops vfs_file_ops_t
 struct vfs_file_ops typedef
 
typedef struct vfs_dir_ops vfs_dir_ops_t
 struct vfs_dir_ops typedef
 
typedef struct vfs_file_system_ops vfs_file_system_ops_t
 struct vfs_file_system_ops typedef
 
typedef struct vfs_mount_struct vfs_mount_t
 struct vfs_mount_struct typedef
 

Functions

void vfs_bind_stdio (void)
 Allocate and bind file descriptors for STDIN, STDERR, and STDOUT. More...
 
int vfs_close (int fd)
 Close an open file. More...
 
int vfs_fcntl (int fd, int cmd, int arg)
 Query/set options on an open file. More...
 
int vfs_fstat (int fd, struct stat *buf)
 Get status of an open file. More...
 
int vfs_fstatvfs (int fd, struct statvfs *buf)
 Get file system status of the file system containing an open file. More...
 
int vfs_dstatvfs (vfs_DIR *dirp, struct statvfs *buf)
 Get file system status of the file system containing an open directory. More...
 
off_t vfs_lseek (int fd, off_t off, int whence)
 Seek to position in file. More...
 
int vfs_open (const char *name, int flags, mode_t mode)
 Open a file. More...
 
ssize_t vfs_read (int fd, void *dest, size_t count)
 Read bytes from an open file. More...
 
ssize_t vfs_write (int fd, const void *src, size_t count)
 Write bytes to an open file. More...
 
ssize_t vfs_write_iol (int fd, const iolist_t *iolist)
 Write bytes from an iolist to an open file. More...
 
int vfs_fsync (int fd)
 Synchronize a file on storage Any pending writes are written out to storage. More...
 
int vfs_opendir (vfs_DIR *dirp, const char *dirname)
 Open a directory for reading with readdir. More...
 
int vfs_readdir (vfs_DIR *dirp, vfs_dirent_t *entry)
 Read a single entry from the open directory dirp and advance the read position by one. More...
 
int vfs_closedir (vfs_DIR *dirp)
 Close an open directory. More...
 
int vfs_format (vfs_mount_t *mountp)
 Format a file system. More...
 
int vfs_mount (vfs_mount_t *mountp)
 Mount a file system. More...
 
int vfs_mount_by_path (const char *path)
 Mount a file system with a pre-configured mount path. More...
 
int vfs_unmount_by_path (const char *path)
 Unmount a file system with a pre-configured mount path. More...
 
int vfs_rename (const char *from_path, const char *to_path)
 Rename a file. More...
 
int vfs_umount (vfs_mount_t *mountp)
 Unmount a mounted file system. More...
 
int vfs_unlink (const char *name)
 Unlink (delete) a file from a mounted file system. More...
 
int vfs_mkdir (const char *name, mode_t mode)
 Create a directory on the file system. More...
 
int vfs_rmdir (const char *name)
 Remove a directory from the file system. More...
 
int vfs_stat (const char *restrict path, struct stat *restrict buf)
 Get file status. More...
 
int vfs_statvfs (const char *restrict path, struct statvfs *restrict buf)
 Get file system status. More...
 
int vfs_bind (int fd, int flags, const vfs_file_ops_t *f_op, void *private_data)
 Allocate a new file descriptor and give it file operations. More...
 
int vfs_normalize_path (char *buf, const char *path, size_t buflen)
 Normalize a path. More...
 
const vfs_mount_tvfs_iterate_mounts (const vfs_mount_t *cur)
 Iterate through all mounted file systems. More...
 
bool vfs_iterate_mount_dirs (vfs_DIR *dir)
 Iterate through all mounted file systems by their root directories. More...
 
const vfs_file_tvfs_file_get (int fd)
 Get information about the file for internal purposes. More...
 
int vfs_sysop_stat_from_fstat (vfs_mount_t *mountp, const char *restrict path, struct stat *restrict buf)
 Implementation of stat using fstat More...
 

Variables

const vfs_file_ops_t mtd_vfs_ops
 MTD driver for VFS.
 
#define _MAX(a, b)   ((a) > (b) ? (a) : (b))
 MAX functions for internal use.
 
#define MAX4(a, b, c, d)   _MAX(_MAX((a), (b)), _MAX((c),(d)))
 
#define FATFS_VFS_DIR_BUFFER_SIZE   (1)
 VFS parameters for FAT.
 
#define FATFS_VFS_FILE_BUFFER_SIZE   (1)
 
#define LITTLEFS_VFS_DIR_BUFFER_SIZE   (1)
 VFS parameters for littlefs.
 
#define LITTLEFS_VFS_FILE_BUFFER_SIZE   (1)
 
#define LITTLEFS2_VFS_DIR_BUFFER_SIZE   (1)
 VFS parameters for littlefs2.
 
#define LITTLEFS2_VFS_FILE_BUFFER_SIZE   (1)
 
#define SPIFFS_VFS_DIR_BUFFER_SIZE   (1)
 VFS parameters for spiffs.
 
#define SPIFFS_VFS_FILE_BUFFER_SIZE   (1)
 

Macro Definition Documentation

◆ VFS_AUTO_MOUNT

#define VFS_AUTO_MOUNT (   type,
  mtd,
  path,
  idx 
)
Value:
static type ## _desc_t fs_desc_ ## idx = mtd; \
XFA(vfs_mountpoints_xfa, 0) \
vfs_mount_t _mount_mtd_ ## idx = { \
.fs = &type ## _file_system, \
.mount_point = path, \
.private_data = &fs_desc_ ## idx, \
}
#define XFA(xfa_name, prio)
Define variable in writable cross-file array.
Definition: xfa.h:142

Define an automatic mountpoint.

Parameters
[in]typefile system type Can be littlefs, littlefs2, spiffs or fatfs

Internally, file systems supporting this must name their vfs_file_system_t ${TYPE}_file_system, and must use a type named ${TYPE}_desc_t for their private data

Parameters
[in]mtdfile system backed device configuration
[in]pathMount path
[in]idxUnique index of the mount point

Definition at line 282 of file vfs.h.

◆ VFS_DIR_BUFFER_SIZE

#define VFS_DIR_BUFFER_SIZE
Value:
)
#define SPIFFS_VFS_DIR_BUFFER_SIZE
VFS parameters for spiffs.
Definition: vfs.h:172
#define LITTLEFS_VFS_DIR_BUFFER_SIZE
VFS parameters for littlefs.
Definition: vfs.h:146
#define LITTLEFS2_VFS_DIR_BUFFER_SIZE
VFS parameters for littlefs2.
Definition: vfs.h:159
#define FATFS_VFS_DIR_BUFFER_SIZE
VFS parameters for FAT.
Definition: vfs.h:133

Size of buffer space in vfs_DIR.

This space is needed to avoid dynamic memory allocations for some file systems where a single pointer is not enough space for its directory stream state, e.g. SPIFFS.

Guidelines:

SPIFFS requires a sizeof(spiffs_DIR) (6-16 bytes, depending on target platform and configuration) buffer for its DIR struct.

Attention
File system developers: If your file system requires a buffer for DIR streams that is larger than a single pointer or int variable, ensure that you have a preprocessor check in your header file (so that it is impossible to attempt to mount the file system without running into a compiler error):
#if VFS_DIR_BUFFER_SIZE < 123
#error VFS_DIR_BUFFER_SIZE is too small, at least 123 bytes is required
#endif
Put the check in the public header file (.h), do not put the check in the implementation (.c) file.

Definition at line 212 of file vfs.h.

◆ VFS_FILE_BUFFER_SIZE

#define VFS_FILE_BUFFER_SIZE
Value:
MAX4(FATFS_VFS_FILE_BUFFER_SIZE, \
LITTLEFS_VFS_FILE_BUFFER_SIZE, \
LITTLEFS2_VFS_FILE_BUFFER_SIZE,\
SPIFFS_VFS_FILE_BUFFER_SIZE \
)

Size of buffer space in vfs_file_t.

Same as with VFS_DIR_BUFFER_SIZE some file systems (e.g. FatFs) require more space to store data about their files.

Guidelines are same as with VFS_DIR_BUFFER_SIZE, so add the following snippet to your fs header:

Attention
#if VFS_FILE_BUFFER_SIZE < 123
#error VFS_FILE_BUFFER_SIZE is too small, at least 123 bytes is required
#endif
Put the check in the public header file (.h), do not put the check in the implementation (.c) file.

Definition at line 239 of file vfs.h.

◆ VFS_MTD

#define VFS_MTD (   mtd)    { .dev = &mtd.base }

Helper macro for VFS_AUTO_MOUNT.

Parameters
[in]mtdMTD device to use for filesystem

Definition at line 267 of file vfs.h.

◆ VFS_NAME_MAX

#define VFS_NAME_MAX   (31)

Maximum length of the name in a vfs_dirent_t (not including terminating null)

Maximum number of bytes in a filename (not including terminating null).

Similar to the POSIX macro NAME_MAX

Definition at line 254 of file vfs.h.

Function Documentation

◆ vfs_bind()

int vfs_bind ( int  fd,
int  flags,
const vfs_file_ops_t f_op,
void *  private_data 
)

Allocate a new file descriptor and give it file operations.

The new fd will be initialized with pointers to the given f_op file operations table and private_data.

This function can be used to give file-like functionality to devices, e.g. UART.

private_data can be used for passing instance information to the file operation handlers in f_op.

Parameters
[in]fdDesired fd number, use VFS_ANY_FD for any available fd
[in]flagsnot implemented yet
[in]f_oppointer to file operations table
[in]private_dataopaque pointer to private data
Returns
fd number on success (>= 0)
<0 on error

◆ vfs_bind_stdio()

void vfs_bind_stdio ( void  )

Allocate and bind file descriptors for STDIN, STDERR, and STDOUT.

This function is meant to be called once during system initialization time. It is typically called from the initialization of the selected STDIO implementation.

◆ vfs_close()

int vfs_close ( int  fd)

Close an open file.

Parameters
[in]fdfd number to close
Returns
0 on success
<0 on error

◆ vfs_closedir()

int vfs_closedir ( vfs_DIR dirp)

Close an open directory.

Attention
Calling vfs_closedir on an uninitialized vfs_DIR is forbidden and may lead to file system corruption and random system failures.
Parameters
[in]dirppointer to open directory
Returns
0 on success
<0 on error, the directory stream dirp should be considered invalid

◆ vfs_dstatvfs()

int vfs_dstatvfs ( vfs_DIR dirp,
struct statvfs buf 
)

Get file system status of the file system containing an open directory.

Parameters
[in]dirppointer to open directory
[out]bufpointer to statvfs struct to fill
Returns
0 on success
<0 on error

◆ vfs_fcntl()

int vfs_fcntl ( int  fd,
int  cmd,
int  arg 
)

Query/set options on an open file.

Parameters
[in]fdfd number to operate on
[in]cmdfcntl command, see man 3p fcntl
[in]argargument to fcntl command, see man 3p fcntl
Returns
0 on success
<0 on error

◆ vfs_file_get()

const vfs_file_t* vfs_file_get ( int  fd)

Get information about the file for internal purposes.

Attention
Not thread safe! Do not modify any of the fields in the returned struct.
Note
For file descriptor internal usage only.

◆ vfs_format()

int vfs_format ( vfs_mount_t mountp)

Format a file system.

mountp should have been populated in advance with a file system driver, a mount point, and private_data (if the file system driver uses one).

Precondition
mountp must not be mounted
Parameters
[in]mountppointer to the mount structure of the filesystem to format
Returns
0 on success
<0 on error

◆ vfs_fstat()

int vfs_fstat ( int  fd,
struct stat *  buf 
)

Get status of an open file.

Parameters
[in]fdfd number obtained from vfs_open
[out]bufpointer to stat struct to fill
Returns
0 on success
<0 on error

◆ vfs_fstatvfs()

int vfs_fstatvfs ( int  fd,
struct statvfs buf 
)

Get file system status of the file system containing an open file.

Parameters
[in]fdfd number obtained from vfs_open
[out]bufpointer to statvfs struct to fill
Returns
0 on success
<0 on error

◆ vfs_fsync()

int vfs_fsync ( int  fd)

Synchronize a file on storage Any pending writes are written out to storage.

Parameters
[in]fdfd number obtained from vfs_open
Returns
0 on success
<0 on error

◆ vfs_iterate_mount_dirs()

bool vfs_iterate_mount_dirs ( vfs_DIR dir)

Iterate through all mounted file systems by their root directories.

Unlike vfs_iterate_mounts, this is thread safe, and allows thread safe access to the mount point's stats through vfs_dstatvfs. If mounts or unmounts happen while iterating, this is guaranteed to report all file systems that stayed mounted, and may report any that are transiently mounted for up to as often as they are (re)mounted. Note that the volume being reported can not be unmounted as dir is an open directory.

Zero-initialize dir to start. As long as true is returned, dir is a valid directory on which the user can call vfs_readdir or vfs_dstatvfs (or even peek at its .mp if they dare ignore the warning in vfs_DIR).

Users MUST NOT call vfs_closedir if they intend to keep iterating, but MUST call it when aborting iteration.

Note that this requires all enumerated file systems to support the opendir vfs_dir_ops; any file system that does not support that will prematurely terminate the mount point enumeration.

See also
sc_vfs.c (df command) for a usage example
Parameters
[in,out]dirThe root directory of the discovered mount point
Returns
true if another file system is mounted; dir then contains an open directory.
false if the file system list is exhausted; dir is uninitialized then.

◆ vfs_iterate_mounts()

const vfs_mount_t* vfs_iterate_mounts ( const vfs_mount_t cur)

Iterate through all mounted file systems.

Attention
Not thread safe! Do not mix calls to this function with other calls which modify the mount table, such as vfs_mount() and vfs_umount()

Set cur to NULL to start from the beginning

Deprecated:
This will become an internal-only function after the 2022.04 release, use vfs_iterate_mount_dirs instead.
Parameters
[in]curcurrent iterator value
Returns
Pointer to next mounted file system in list after cur
NULL if cur is the last element in the list

◆ vfs_lseek()

off_t vfs_lseek ( int  fd,
off_t  off,
int  whence 
)

Seek to position in file.

whence determines the function of the seek and should be set to one of the following values:

  • SEEK_SET: Seek to absolute offset off
  • SEEK_CUR: Seek to current location + off
  • SEEK_END: Seek to end of file + off
Parameters
[in]fdfd number obtained from vfs_open
[in]offseek offset
[in]whencedetermines the seek method, see detailed description
Returns
the new seek location in the file on success
<0 on error

◆ vfs_mkdir()

int vfs_mkdir ( const char *  name,
mode_t  mode 
)

Create a directory on the file system.

Parameters
[in]namename of the directory to create
[in]modefile creation mode bits
Returns
0 on success
<0 on error

◆ vfs_mount()

int vfs_mount ( vfs_mount_t mountp)

Mount a file system.

mountp should have been populated in advance with a file system driver, a mount point, and private_data (if the file system driver uses one).

Parameters
[in]mountppointer to the mount structure of the file system to mount
Returns
0 on success
<0 on error

◆ vfs_mount_by_path()

int vfs_mount_by_path ( const char *  path)

Mount a file system with a pre-configured mount path.

Note
This assumes mount points have been configured with VFS_AUTO_MOUNT.
Warning
If the vfs_auto_format is used a format attempt will be made if the mount fails.
Parameters
[in]pathPath of the pre-configured mount point
Returns
0 on success
<0 on error

◆ vfs_normalize_path()

int vfs_normalize_path ( char *  buf,
const char *  path,
size_t  buflen 
)

Normalize a path.

Normalizing a path means to remove all relative components ("..", ".") and any double slashes.

Note
buf is allowed to overlap path if &buf[0] <= &path[0]
Attention
path must be an absolute path (starting with / )
Parameters
[out]bufbuffer to store normalized path
[in]pathpath to normalize
[in]buflenavailable space in buf
Returns
number of path components in the normalized path on success
<0 on error

◆ vfs_open()

int vfs_open ( const char *  name,
int  flags,
mode_t  mode 
)

Open a file.

Parameters
[in]namefile name to open
[in]flagsflags for opening, see man 3p open
[in]modefile mode
Returns
fd number on success (>= 0)
<0 on error

◆ vfs_opendir()

int vfs_opendir ( vfs_DIR dirp,
const char *  dirname 
)

Open a directory for reading with readdir.

The data in *dirp will be initialized by vfs_opendir

Parameters
[out]dirppointer to directory stream struct for storing the state
[in]dirnamenull-terminated name of the dir to open, absolute file system path
Returns
0 on success
<0 on error

◆ vfs_read()

ssize_t vfs_read ( int  fd,
void *  dest,
size_t  count 
)

Read bytes from an open file.

Parameters
[in]fdfd number obtained from vfs_open
[out]destdestination buffer to hold the file contents
[in]countmaximum number of bytes to read
Returns
number of bytes read on success
<0 on error

For simple cases of only a single read from a file, the vfs_file_to_buffer function can be used.

◆ vfs_readdir()

int vfs_readdir ( vfs_DIR dirp,
vfs_dirent_t entry 
)

Read a single entry from the open directory dirp and advance the read position by one.

entry will be populated with information about the next entry in the directory stream dirp

Attention
Calling vfs_readdir on an uninitialized vfs_DIR is forbidden and may lead to file system corruption and random system failures.
Parameters
[in]dirppointer to open directory
[out]entrydirectory entry information
Returns
1 if entry was updated
0 if dirp has reached the end of the directory index
<0 on error

◆ vfs_rename()

int vfs_rename ( const char *  from_path,
const char *  to_path 
)

Rename a file.

The file from_path will be renamed to to_path

Note
it is not possible to rename files across different file system
Parameters
[in]from_pathabsolute path to existing file
[in]to_pathabsolute path to destination
Returns
0 on success
<0 on error

◆ vfs_rmdir()

int vfs_rmdir ( const char *  name)

Remove a directory from the file system.

Only empty directories may be removed.

Parameters
[in]namename of the directory to remove
Returns
0 on success
<0 on error

◆ vfs_stat()

int vfs_stat ( const char *restrict  path,
struct stat *restrict  buf 
)

Get file status.

Parameters
[in]pathpath to file being queried
[out]bufpointer to stat struct to fill
Returns
0 on success
<0 on error

◆ vfs_statvfs()

int vfs_statvfs ( const char *restrict  path,
struct statvfs *restrict  buf 
)

Get file system status.

path can be any path that resolves to the file system being queried, it does not have to be an existing file.

Parameters
[in]pathpath to a file on the file system being queried
[out]bufpointer to statvfs struct to fill
Returns
0 on success
<0 on error

◆ vfs_sysop_stat_from_fstat()

int vfs_sysop_stat_from_fstat ( vfs_mount_t mountp,
const char *restrict  path,
struct stat *restrict  buf 
)

Implementation of stat using fstat

This helper can be used by file system drivers that do not have any more efficient implementation of fs_op::stat than opening the file and running f_op::fstat on it.

It can be set as fs_op::stat by a file system driver, provided it implements f_op::open and f_op::fstat and f_op::close, and its open accepts NULL in the abs_path position.

◆ vfs_umount()

int vfs_umount ( vfs_mount_t mountp)

Unmount a mounted file system.

This will fail if there are any open files or directories on the mounted file system

Parameters
[in]mountppointer to the mount structure of the file system to unmount
Returns
0 on success
<0 on error

◆ vfs_unlink()

int vfs_unlink ( const char *  name)

Unlink (delete) a file from a mounted file system.

Parameters
[in]namename of file to delete
Returns
0 on success
<0 on error

◆ vfs_unmount_by_path()

int vfs_unmount_by_path ( const char *  path)

Unmount a file system with a pre-configured mount path.

Note
This assumes mount points have been configured with VFS_AUTO_MOUNT.
Parameters
[in]pathPath of the pre-configured mount point
Returns
0 on success
<0 on error

◆ vfs_write()

ssize_t vfs_write ( int  fd,
const void *  src,
size_t  count 
)

Write bytes to an open file.

Parameters
[in]fdfd number obtained from vfs_open
[in]srcpointer to source buffer
[in]countmaximum number of bytes to write
Returns
number of bytes written on success
<0 on error

For simple cases of only a single write to a file, the vfs_file_from_buffer function can be used.

◆ vfs_write_iol()

ssize_t vfs_write_iol ( int  fd,
const iolist_t iolist 
)

Write bytes from an iolist to an open file.

Parameters
[in]fdfd number obtained from vfs_open
[in]iolistiolist to read from
Returns
number of bytes written on success
<0 on error