Single namespace of device nodes, RAM directories, RAM files, and mounted filesystems.
More...
|
| 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.
|
| |
|
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.
|
| |
|
|
#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.
|
| |
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.
◆ 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
-
| name | Entry name without its parent path. Valid only for the duration of the call. |
| is_directory | true if the entry is a directory. |
| context | Value passed to vfs_list(). |
- Returns
- 0 to continue, or nonzero to stop and make vfs_list() return this value.
◆ vfs_init()
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()
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
-
◆ vfs_find_node()
Look up a node by path.
- Parameters
-
| name | Path 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
-
| base | Existing absolute directory. Used only when path is relative. |
| path | Path to resolve. Must not be empty. |
| [out] | result | Canonical absolute path. Must hold VFS_PATH_CAPACITY bytes. |
- Return values
-
| 0 | result holds the resolved path. |
| -1 | errno 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
-
| path | Directory to create. Its parent must exist. |
- Return values
-
| 0 | The directory was created. |
| -1 | errno 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
-
- Return values
-
| 0 | The directory was removed and its memory freed. |
| -1 | errno 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
-
- Return values
-
| 0 | The file was removed. |
| -1 | errno 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()
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
-
| path | Directory to list. |
| visitor | Function called for each child. |
| context | Value 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
-
| name | Path to open, resolved from /. |
| flags | One 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()
Release a descriptor.
- Parameters
-
- 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
-
| fd | Open descriptor. |
| buf | Destination of at least len bytes. May be NULL only if len is 0. |
| len | Maximum 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
-
| fd | Open descriptor. |
| buf | Source of at least len bytes. May be NULL only if len is 0. |
| len | Number 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
-
| fd | Open descriptor. |
| request | Device-specific request code. |
| arg | Device-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
-
| fd | Open descriptor. |
| offset | Offset relative to whence. |
| whence | SEEK_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()
Get the node behind an open descriptor.
- Parameters
-
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
-
| path | Path to inspect, resolved from /. |
| [out] | stat | Result. Must not be NULL. |
- Return values
-
| 0 | stat is filled in. |
| -1 | errno is ENOENT, ENOTDIR, ENAMETOOLONG, or set by the mounted filesystem. |
◆ vfs_fstat()
Report the type and size of an open descriptor.
- Parameters
-
| fd | Open descriptor. |
| [out] | stat | Result. 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
-
| path | Absolute path of the mount point. Its parent must exist and the path must not. The string is copied. |
| ops | Filesystem operations. Must remain valid for the rest of the program. |
| fs | Filesystem instance passed to every operation. |
- Return values
-
| 0 | The filesystem is mounted. |
| -1 | errno is EINVAL (missing argument), EEXIST, ENOENT, ENOTDIR, ENAMETOOLONG, EBUSY (inside another mount), or ENOSPC when CONFIG_HOMECORE_VFS_MAX_MOUNTS mounts exist. |