Skip to content

Filesystem

The oveRTOS filesystem module provides a VFS abstraction that maps POSIX-like file and directory operations onto the underlying RTOS storage backend. Volumes are mounted by path prefix and all subsequent operations use absolute path strings. The same application code runs unchanged across FatFS (SD card), LittleFS, NuttX VFS, and POSIX host filesystem.

Architecture

graph TD
    APP["Application Code"]
    API["ove_fs API<br/><small>ove/fs.h</small>"]
    CFG["CONFIG dispatch<br/><small>OVE_FS_O_* flags / path prefix</small>"]

    subgraph Backends
        FATFS["FatFS<br/><small>SD card / eMMC</small>"]
        LITTLEFS["LittleFS<br/><small>NOR/NAND flash</small>"]
        NUTTX["NuttX VFS<br/><small>/dev/mmcsd / mtdblock</small>"]
        POSIX["POSIX<br/><small>Host development</small>"]
    end

    subgraph Hardware
        SPI["SPI / SDIO<br/><small>FreeRTOS / Zephyr</small>"]
        FLASH["SPI Flash<br/><small>FreeRTOS / Zephyr</small>"]
        HW_NUTTX["NuttX block driver"]
        HOSTFS["Host Filesystem"]
    end

    APP --> API --> CFG
    CFG --> FATFS --> SPI
    CFG --> LITTLEFS --> FLASH
    CFG --> NUTTX --> HW_NUTTX
    CFG --> POSIX --> HOSTFS

    style APP fill:#4a9,stroke:#333,color:#fff
    style API fill:#48b,stroke:#333,color:#fff
    style CFG fill:#666,stroke:#333,color:#fff

File Operations

Function Signature Description
ove_fs_mount (dev_path, mount_point) → int Mount a storage device at a virtual path prefix
ove_fs_unmount (mount_point) → void Unmount a previously mounted device; flush pending data
ove_fs_open_init (file, storage, path, flags) → int Open using caller-supplied static storage (no heap)
ove_fs_close_deinit (file) → int Close a statically-allocated file handle
ove_fs_open (file, path, flags) → int Open a file (heap or backend-managed allocation)
ove_fs_close (file) → int Close a file handle returned by ove_fs_open
ove_fs_read (file, buf, count, bytes_read) → int Read bytes from an open file
ove_fs_write (file, buf, count, bytes_written) → int Write bytes to an open file
ove_fs_seek (file, offset, whence) → int Reposition the file read/write offset
ove_fs_tell (file) → long Return the current file position
ove_fs_size (file, out_size) → int Query the total size of an open file
ove_fs_unlink (path) → int Delete a file by path
ove_fs_rename (old_path, new_path) → int Rename or move a file

Directory Operations

Function Signature Description
ove_fs_opendir_init (dir, storage, path) → int Open a directory using caller-supplied static storage
ove_fs_closedir_deinit (dir) → int Close a statically-allocated directory handle
ove_fs_opendir (dir, path) → int Open a directory (heap or backend-managed allocation)
ove_fs_readdir (dir, entry) → int Read the next entry; returns OVE_ERR_EOF when exhausted
ove_fs_closedir (dir) → int Close a directory handle returned by ove_fs_opendir

Each ove_fs_readdir call fills an ove_dirent structure:

struct ove_dirent {
    char         name[256]; /* null-terminated entry name (not full path) */
    unsigned int size;      /* file size in bytes; 0 for directories       */
    int          is_dir;    /* non-zero if the entry is a directory         */
};

Open Flags

Flags are combined with bitwise OR and passed to ove_fs_open or ove_fs_open_init.

Flag Value Description
OVE_FS_O_READ 0x01 Open for reading
OVE_FS_O_WRITE 0x02 Open for writing
OVE_FS_O_CREATE 0x04 Create the file if it does not exist
OVE_FS_O_APPEND 0x08 Seek to end of file before each write

Seek Whence Constants

Constant Value Description
OVE_FS_SEEK_SET 0 Seek relative to the beginning of the file
OVE_FS_SEEK_CUR 1 Seek relative to the current file position
OVE_FS_SEEK_END 2 Seek relative to the end of the file

Allocation Strategies

File and directory handles follow the same dual-allocation pattern used throughout oveRTOS.

Static (zero-heap) — open_init / close_deinit:

The caller declares storage with OVE_FILE_DEFINE() and passes it to ove_fs_open_init. No heap allocation is performed; the storage must remain valid for the lifetime of the open file. Use this on targets where CONFIG_OVE_ZERO_HEAP=y.

static ove_file_storage_t file_storage;

ove_file_t f;
ove_fs_open_init(&f, &file_storage, "/sd/data.bin", OVE_FS_O_READ);
/* ... read ... */
ove_fs_close_deinit(f);

Heap — open / close:

Available when OVE_HEAP_FS is defined (i.e. CONFIG_OVE_ZERO_HEAP is not set). The backend allocates the handle from the RTOS heap.

ove_file_t f;
ove_fs_open(&f, "/sd/data.bin", OVE_FS_O_READ);
/* ... read ... */
ove_fs_close(f);

Both ove_fs_opendir / ove_fs_closedir and ove_fs_opendir_init / ove_fs_closedir_deinit follow the same pattern for directories.

Example: Reading a WAV File from SD Card

#include "ove/ove.h"

/* Mount the SD card (FatFS backend, SDIO interface) */
ove_fs_mount("/dev/sdcard", "/sd");

ove_file_t f;
if (ove_fs_open(&f, "/sd/sample.wav", OVE_FS_O_READ) != OVE_OK) {
    OVE_LOG_ERR("Failed to open WAV file");
    return;
}

/* Read WAV header (44 bytes) */
uint8_t header[44];
size_t nr;
ove_fs_read(f, header, sizeof(header), &nr);

/* Determine file size and audio data length */
size_t file_size;
ove_fs_size(f, &file_size);
size_t audio_len = file_size - sizeof(header);

/* Stream audio data in 512-byte chunks */
uint8_t chunk[512];
while (audio_len > 0) {
    size_t to_read = audio_len < sizeof(chunk) ? audio_len : sizeof(chunk);
    ove_fs_read(f, chunk, to_read, &nr);
    /* feed nr bytes of PCM to the audio graph ... */
    audio_len -= nr;
}

ove_fs_close(f);
ove_fs_unmount("/sd");

Kconfig Options

Option Default Description
CONFIG_OVE_FS n Enable the filesystem abstraction layer
Header Contents
ove/fs.h Mount/unmount, file handle types, open flags, seek constants, all file and directory operations