HomeCore 0.1.3 (07b5544)
Bare-metal personal computer firmware for Cortex-M
Loading...
Searching...
No Matches
Virtual file system

Single namespace of device nodes, RAM directories, RAM files, and mounted filesystems. More...

Collaboration diagram for Virtual file system:

Data Structures

struct  vfs_ops_t
 Device operations. More...
 
struct  vfs_node
 Named entry in the VFS namespace. More...
 
struct  vfs_stat_t
 File type and size reported by vfs_stat() and vfs_fstat(). More...
 
struct  vfs_fs_ops_t
 Operations a mounted filesystem provides; every one is required. More...
 

Nodes and drivers

typedef struct vfs_node vfs_node_t
 VFS node; see struct vfs_node.
 
void vfs_init (void)
 Obsolete initializer; currently does nothing.
 
void vfs_register_node (vfs_node_t *node)
 Add a node to the namespace.
 
vfs_node_t * vfs_find_node (const char *name)
 Look up a node by path.
 

Namespace operations

typedef int(* vfs_directory_visitor_t) (const char *name, bool is_directory, void *context)
 Visitor called for each directory entry by vfs_list().
 
int vfs_resolve_path (const char *base, const char *path, char result[VFS_PATH_CAPACITY])
 Resolve a path against an explicit base directory.
 
int vfs_mkdir (const char *path)
 Create an empty directory.
 
int vfs_rmdir (const char *path)
 Remove an empty directory created by vfs_mkdir().
 
int vfs_unlink (const char *path)
 Remove a file: a RAM file, whose contents are freed, or a file on a mounted filesystem.
 
int vfs_list (const char *path, vfs_directory_visitor_t visitor, void *context)
 Visit the direct children of a directory.
 

Descriptor operations

int vfs_open (const char *name, int flags)
 Open a node and allocate the lowest free descriptor.
 
int vfs_close (int fd)
 Release a descriptor.
 
int vfs_read (int fd, void *buf, unsigned len)
 Read from a descriptor.
 
int vfs_write (int fd, const void *buf, unsigned len)
 Write to a descriptor.
 
int vfs_ioctl (int fd, unsigned request, void *arg)
 Forward a control request to a device.
 
int vfs_lseek (int fd, int offset, int whence)
 Move a descriptor's position.
 
vfs_node_t * vfs_fd_node (int fd)
 Get the node behind an open descriptor.
 
int vfs_stat (const char *path, vfs_stat_t *stat)
 Report the type and size of a path.
 
int vfs_fstat (int fd, vfs_stat_t *stat)
 Report the type and size of an open descriptor.
 

Mounted filesystems

A mounted filesystem owns everything below its mount point.

Paths passed to its operations are relative to the mount point and always start with / (the mount point itself is /). Operations return 0 or a byte count on success and -1 with errno set on failure, like the corresponding vfs_* functions. The VFS resolves . and .., rejects reads and writes the access mode forbids, zero-length transfers, and NULL buffers, and allocates the descriptor; the filesystem handles O_CREAT, O_EXCL, O_TRUNC, and O_APPEND. Descriptors on mounted files do not support vfs_ioctl() (ENOTTY).

int vfs_mount (const char *path, const vfs_fs_ops_t *ops, void *fs)
 Attach a filesystem at a new mount point.
 

Limits

#define VFS_SNAPSHOT_CAPACITY   32
 Maximum content size of a snapshot device, in bytes.
 
#define VFS_PATH_CAPACITY   128
 Path buffer size including the terminator; paths hold at most 127 bytes.
 

Detailed Description

Single namespace of device nodes, RAM directories, RAM files, and mounted filesystems.

Nodes are kept in one list and are named by canonical absolute paths. RAM directories, RAM files, and descriptors are allocated from the heap when created or opened and freed when removed or closed; the Kconfig maxima cap how many can exist. RAM file contents also use the heap and are lost on reset. Filesystems attached with vfs_mount() own every path below their mount point; see Filesystems. libc I/O reaches the VFS through the newlib hooks in src/kernel/syscalls.c. The VFS is not reentrant and must not be called from interrupt handlers.

Entry Created by Has a node Contents
Device A driver, vfs_register_node() Yes Stream or snapshot operations
RAM directory vfs_mkdir() outside mounts Yes Child entries
RAM file vfs_open() with O_CREAT outside mounts Yes Heap buffer
Mount point vfs_mount() Yes (a directory) The filesystem's root
Path below a mount point The filesystem No Owned by the filesystem

Code that needs a type or size uses vfs_stat() or vfs_fstat(), which work for every entry; vfs_find_node() and vfs_fd_node() see nodes only. The Files and storage page describes path resolution, descriptors, and the filesystems in detail.

Paths passed to these functions are resolved from /, even when they do not start with a slash. To honor a session's working directory, resolve the path with vfs_resolve_path() first.

Return convention: failures return -1 with errno set, except where a function documents otherwise. Descriptor functions return -1 for an out-of-range descriptor and -2 for a closed descriptor without setting errno. Callers should therefore test for a negative result.

Typedef Documentation

◆ vfs_node_t

typedef struct vfs_node vfs_node_t

VFS node; see struct vfs_node.

Named entry in the VFS namespace.

Drivers define device nodes statically, setting name, ops, and optionally driver_data, and pass them to vfs_register_node(). The VFS manages the other fields.

◆ vfs_directory_visitor_t

typedef int(* vfs_directory_visitor_t) (const char *name, bool is_directory, void *context)

Visitor called for each directory entry by vfs_list().

Parameters
nameEntry name without its parent path. Valid only for the duration of the call.
is_directorytrue if the entry is a directory.
contextValue passed to vfs_list().
Returns
0 to continue, or nonzero to stop and make vfs_list() return this value.

Function Documentation

◆ vfs_init()

void vfs_init ( void  )

Obsolete initializer; currently does nothing.

VFS state is statically initialized and devices are registered during startup. Do not call it after nodes are registered.

◆ vfs_register_node()

void vfs_register_node ( vfs_node_t *  node)

Add a node to the namespace.

The node is linked by pointer and cannot be unregistered, so it must remain valid for the rest of the program. A NULL node, a NULL name, or a name that is already registered is silently ignored. The parent directory is not checked. Device nodes belong under /dev.

Parameters
nodeNode to register.

◆ vfs_find_node()

vfs_node_t * vfs_find_node ( const char *  name)

Look up a node by path.

Parameters
namePath to resolve from /. Intermediate components must be existing directories.
Returns
The node, or NULL with errno set to ENOENT, ENOTDIR, or ENAMETOOLONG. Paths below a mount point have no node and return NULL with ENOENT even when they exist; use vfs_stat() instead.

◆ vfs_resolve_path()

int vfs_resolve_path ( const char *  base,
const char *  path,
char  result[VFS_PATH_CAPACITY] 
)

Resolve a path against an explicit base directory.

Absolute paths ignore base. Repeated slashes, ., and .. are normalized. Every intermediate component must be an existing directory, including directories inside mounted filesystems, but the final component may not exist. Other VFS operations remain rooted at / for relative arguments.

Parameters
baseExisting absolute directory. Used only when path is relative.
pathPath to resolve. Must not be empty.
[out]resultCanonical absolute path. Must hold VFS_PATH_CAPACITY bytes.
Return values
0result holds the resolved path.
-1errno is EINVAL (missing argument, empty path, or a relative path with a missing or relative base), ENOENT, ENOTDIR, or ENAMETOOLONG.

◆ vfs_mkdir()

int vfs_mkdir ( const char *  path)

Create an empty directory.

Below a mount point, the filesystem creates the directory; elsewhere it is a RAM directory.

Parameters
pathDirectory to create. Its parent must exist.
Return values
0The directory was created.
-1errno is EEXIST, ENOENT, ENOTDIR, ENAMETOOLONG, ENOSPC when CONFIG_HOMECORE_VFS_MAX_DIRECTORIES RAM directories exist or the filesystem is full, ENOMEM when the entry cannot be allocated, or set by the filesystem.

◆ vfs_rmdir()

int vfs_rmdir ( const char *  path)

Remove an empty directory created by vfs_mkdir().

Does not check whether a session uses the directory as its working directory; callers must check that themselves.

Parameters
pathDirectory to remove.
Return values
0The directory was removed and its memory freed.
-1errno is ENOENT, ENOTDIR, EBUSY for /, /dev, and mount points, ENOTEMPTY, EROFS for a registered directory that was not created by vfs_mkdir(), or set by the filesystem.

◆ vfs_unlink()

int vfs_unlink ( const char *  path)

Remove a file: a RAM file, whose contents are freed, or a file on a mounted filesystem.

Parameters
pathFile to remove.
Return values
0The file was removed.
-1errno is ENOENT, EISDIR (including a mount point), EPERM for a device node, EBUSY while any descriptor is open on the file, or set by the filesystem.

◆ vfs_list()

int vfs_list ( const char *  path,
vfs_directory_visitor_t  visitor,
void *  context 
)

Visit the direct children of a directory.

Node entries are visited most recently registered first, so a mount point appears in its parent's listing. Below a mount point the filesystem lists its entries in its own order, without . and ... The namespace must not be modified during the visit.

Parameters
pathDirectory to list.
visitorFunction called for each child.
contextValue passed to visitor.
Returns
0 after visiting every child; the visitor's nonzero result if it stopped early; or -1 with errno set to EINVAL for a NULL visitor, ENOENT, ENOTDIR, or set by the filesystem.

◆ vfs_open()

int vfs_open ( const char *  name,
int  flags 
)

Open a node and allocate the lowest free descriptor.

O_CREAT creates a RAM file when the parent directory exists. O_TRUNC discards a RAM file's contents. Opening a snapshot device captures its content for this descriptor. Below a mount point, the VFS checks the access mode and allocates the descriptor, and the filesystem opens the file and handles O_CREAT, O_EXCL, O_TRUNC, and O_APPEND.

Parameters
namePath to open, resolved from /.
flagsOne of O_RDONLY, O_WRONLY, or O_RDWR, optionally combined with O_CREAT, O_EXCL, O_TRUNC, and O_APPEND from <fcntl.h>.
Returns
A descriptor from 0 to CONFIG_HOMECORE_VFS_MAX_OPEN_FILES - 1; a negative result from the node's open operation; or -1 with errno set to EINVAL (invalid access mode), EACCES (O_TRUNC with O_RDONLY, or write access to a read-only snapshot device), EMFILE, EEXIST, EISDIR, ENOENT, ENOTDIR, ENAMETOOLONG, ENOSPC (CONFIG_HOMECORE_VFS_MAX_RAM_FILES files exist), ENOMEM (the descriptor or new file cannot be allocated; nothing is created or truncated), EIO (snapshot failed), or set by the filesystem.

◆ vfs_close()

int vfs_close ( int  fd)

Release a descriptor.

Parameters
fdDescriptor returned by vfs_open().
Returns
The node's close result, or 0 if it has none; for a mounted file, the filesystem's result, which reports data that could not be written; -1 for an out-of-range descriptor; -2 for a closed descriptor. The descriptor is released in every case.

◆ vfs_read()

int vfs_read ( int  fd,
void *  buf,
unsigned  len 
)

Read from a descriptor.

RAM files and snapshot devices copy from the descriptor's position and advance it. Files on mounted filesystems read through the filesystem. Other nodes forward to their read operation, which may block.

Parameters
fdOpen descriptor.
bufDestination of at least len bytes. May be NULL only if len is 0.
lenMaximum number of bytes to read.
Returns
Bytes read, or 0 at end of file; -1 on failure (errno is EBADF for a write-only file, EFAULT for a NULL buffer, or set by the driver or filesystem); -2 for a closed descriptor.

◆ vfs_write()

int vfs_write ( int  fd,
const void *  buf,
unsigned  len 
)

Write to a descriptor.

RAM files are written at the descriptor's position, or at the end with O_APPEND. A write past the end grows the file and zero-fills any gap. Files on mounted filesystems write through the filesystem, which may return a short count when it fills up. Other nodes forward to their write operation.

Parameters
fdOpen descriptor.
bufSource of at least len bytes. May be NULL only if len is 0.
lenNumber of bytes to write.
Returns
Bytes written; -1 on failure (errno is EBADF for a read-only descriptor or a snapshot device without write, EFAULT, EFBIG beyond CONFIG_HOMECORE_VFS_MAX_FILE_SIZE, ENOMEM, ENOSPC when a mounted filesystem is full, or set by the driver or filesystem); -2 for a closed descriptor.

◆ vfs_ioctl()

int vfs_ioctl ( int  fd,
unsigned  request,
void *  arg 
)

Forward a control request to a device.

Parameters
fdOpen descriptor.
requestDevice-specific request code.
argDevice-specific argument.
Returns
The node's ioctl result; -1 if it has none, or with errno ENOTTY for a file on a mounted filesystem; -2 for a closed descriptor.

◆ vfs_lseek()

int vfs_lseek ( int  fd,
int  offset,
int  whence 
)

Move a descriptor's position.

RAM files accept positions from 0 to CONFIG_HOMECORE_VFS_MAX_FILE_SIZE. Snapshot devices accept positions within the captured content. Files on mounted filesystems follow the filesystem's rules; see FAT filesystem and littlefs filesystem. Other nodes forward to their lseek operation.

Parameters
fdOpen descriptor.
offsetOffset relative to whence.
whenceSEEK_SET, SEEK_CUR, or SEEK_END.
Returns
New position; -1 on failure (errno is EINVAL for an invalid whence or out-of-range position, or set by the driver); -2 for a closed descriptor.

◆ vfs_fd_node()

vfs_node_t * vfs_fd_node ( int  fd)

Get the node behind an open descriptor.

Parameters
fdDescriptor to inspect.

Descriptors on mounted filesystems have no node; use vfs_fstat() for them.

Returns
The node, or NULL with errno set to EBADF for a closed or out-of-range descriptor, or ENOTSUP for a file on a mounted filesystem.

◆ vfs_stat()

int vfs_stat ( const char *  path,
vfs_stat_t *  stat 
)

Report the type and size of a path.

Works for nodes and for paths inside mounted filesystems, which have no node. A path that is neither a directory nor a regular file is a device.

Parameters
pathPath to inspect, resolved from /.
[out]statResult. Must not be NULL.
Return values
0stat is filled in.
-1errno is ENOENT, ENOTDIR, ENAMETOOLONG, or set by the mounted filesystem.

◆ vfs_fstat()

int vfs_fstat ( int  fd,
vfs_stat_t *  stat 
)

Report the type and size of an open descriptor.

Parameters
fdOpen descriptor.
[out]statResult. Must not be NULL.
Returns
0 on success; -1 with errno set to EBADF for a closed or out-of-range descriptor, or set by the mounted filesystem.

◆ vfs_mount()

int vfs_mount ( const char *  path,
const vfs_fs_ops_t *  ops,
void *  fs 
)

Attach a filesystem at a new mount point.

Creates path as a directory node owned by the filesystem. Mount points cannot be removed or nested, and there is no unmount yet.

Parameters
pathAbsolute path of the mount point. Its parent must exist and the path must not. The string is copied.
opsFilesystem operations. Must remain valid for the rest of the program.
fsFilesystem instance passed to every operation.
Return values
0The filesystem is mounted.
-1errno is EINVAL (missing argument), EEXIST, ENOENT, ENOTDIR, ENAMETOOLONG, EBUSY (inside another mount), or ENOSPC when CONFIG_HOMECORE_VFS_MAX_MOUNTS mounts exist.