GitHub - Partakithware/VeloxFS: A single-header C filesystem library, following the STB single-file library convention.

GitHub

Important

The latest branch contains v6 — a full rewrite of the allocation engine tuned for HDD, Flash, and NAND storage. v6 images are not compatible with v5 images (different magic number VLX6). Re-format any existing images. v6 veloxfs_fuse.c covers a little less than the main branch version but works for now. Enjoy! The README below reflects v5(main branch)

v6 Recommended Instead - Click Here

.

Important

The latest branch also contains a Linux Driver (concept) that works!

A single-header C filesystem library, following the

STB

single-file library convention.

Listed on:

SingleFileLibs

The entire filesystem implementation lives in veloxfs.h. The optional veloxfs_fuse.c adapter lets you mount a veloxfs image as a real filesystem on Linux via FUSE. It is not required to use the library. Other examples can be found in

examples

here for different use case examples, for now there is only one.

Ensure you read the issues tab.

———
How it works

veloxfs stores data in a flat binary image (a file, a block device, a memory buffer, or anything you can read and write by offset). The layout is:

[ superblock | FAT | journal | inodes | directory | data blocks ] Block allocation uses a FAT-style singly-linked list. Each inode stores the index of its first block; the FAT maps each block to the next, terminating with a sentinel value. This means files can grow without relocation and fragmentation does not cause data corruption.

Directories are implicit. There is no directory inode — a directory exists if at least one file path begins with that prefix. The FUSE adapter anchors empty directories with a hidden .veloxfs_dir marker file so they survive remount.

———
What it supports

Create, read, write, delete, rename files

Create, delete, rename directories (arbitrarily nested)

File data persists across mount/unmount

Unix-style permissions (uid, gid, mode bits)

Optional write-ahead journal (64-entry circular log)

O(1) directory lookups via an in-memory FNV-1a hash table

fsck to detect and free orphaned blocks

Allocation statistics

What it does not support

Hard links or symbolic links

Extended attributes

File locking

Access control lists

Sparse files

Timestamps with sub-second precision

Concurrent access without external locking (the FUSE adapter adds a mutex; the library itself is single-threaded)

———
Usage

Library only (no FUSE)

In one C file, define the implementation before including the header:

#defineveloxfs_IMPLEMENTATION#include"veloxfs.h"All other files that need the API include it without the define:

#include"veloxfs.h"Minimal example

#defineveloxfs_IMPLEMENTATION#include"veloxfs.h"#include<stdio.h>// Provide two callbacks: read and write at a byte offset.// The backing store can be anything.staticuint8_tstorage[32*1024*1024]; // 32 MB RAM diskstaticintmem_read(void*user, uint64_toff, void*buf, uint32_tn) { memcpy(buf, (uint8_t*)user+off, n); return0; } staticintmem_write(void*user, uint64_toff, constvoid*buf, uint32_tn) { memcpy((uint8_t*)user+off, buf, n); return0; } intmain(void) { veloxfs_ioio= { mem_read, mem_write, storage }; uint64_tblocks=sizeof(storage) / veloxfs_BLOCK_SIZE; veloxfs_format(io, blocks, 0/* journaling off */); veloxfs_handlefs; veloxfs_mount(&fs, io); veloxfs_create(&fs, "/hello.txt", 0644); veloxfs_write_file(&fs, "/hello.txt", "hello", 5); charbuf[16]; uint64_tgot; veloxfs_read_file(&fs, "/hello.txt", buf, sizeof(buf), &got); buf[got] ='\0'; printf("%s\n", buf); // helloveloxfs_unmount(&fs); return0; }Mounting as a real filesystem (Linux, requires libfuse)

# Build gcc -Wall -O2 -pthread veloxfs_fuse.c -o veloxfs_fuse \ `pkg-config fuse --cflags --libs`# Create and format an image dd if=/dev/zero of=veloxfs.img bs=1M count=512 ./veloxfs_fuse --format veloxfs.img # Mount mkdir /tmp/mnt ./veloxfs_fuse veloxfs.img /tmp/mnt -o big_writes,max_write=131072 # Use it normally — cp, mv, mkdir, rm, etc. cp largefile.bin /tmp/mnt/ mkdir /tmp/mnt/docs mv /tmp/mnt/docs /tmp/mnt/documents # Unmount — data persists fusermount -u /tmp/mnt # Remount and verify ./veloxfs_fuse veloxfs.img /tmp/mnt ls /tmp/mnt
———
API reference

Filesystem lifecycle

intveloxfs_format(veloxfs_ioio, uint64_tblock_count, intenable_journal); intveloxfs_mount(veloxfs_handle*fs, veloxfs_ioio); intveloxfs_unmount(veloxfs_handle*fs); intveloxfs_sync(veloxfs_handle*fs); intveloxfs_fsck(veloxfs_handle*fs);File operations

intveloxfs_create(veloxfs_handle*fs, constchar*path, uint32_tmode); intveloxfs_delete(veloxfs_handle*fs, constchar*path); intveloxfs_rename(veloxfs_handle*fs, constchar*old_path, constchar*new_path); intveloxfs_write_file(veloxfs_handle*fs, constchar*path, constvoid*data, uint64_tsize); intveloxfs_read_file(veloxfs_handle*fs, constchar*path, void*out, uint64_tmax, uint64_t*out_size);File handle operations (streaming I/O)

intveloxfs_open(veloxfs_handle*fs, constchar*path, intflags, veloxfs_file*file); intveloxfs_close(veloxfs_file*file); intveloxfs_read(veloxfs_file*file, void*buf, uint64_tcount, uint64_t*bytes_read); intveloxfs_write(veloxfs_file*file, constvoid*buf, uint64_tcount); intveloxfs_seek(veloxfs_file*file, int64_toffset, intwhence); uint64_tveloxfs_tell(veloxfs_file*file); intveloxfs_truncate_handle(veloxfs_file*file, uint64_tnew_size);Metadata and statistics

intveloxfs_stat(veloxfs_handle*fs, constchar*path, veloxfs_stat_t*stat); intveloxfs_statfs(veloxfs_handle*fs, uint64_t*total, uint64_t*used, uint64_t*free); intveloxfs_chmod(veloxfs_handle*fs, constchar*path, uint32_tmode); intveloxfs_chown(veloxfs_handle*fs, constchar*path, uint32_tuid, uint32_tgid); intveloxfs_mkdir(veloxfs_handle*fs, constchar*path, uint32_tmode); intveloxfs_list(veloxfs_handle*fs, constchar*path, veloxfs_list_callbackcb, void*user);Error codes

CodeValueMeaningveloxfs_OK0Successveloxfs_ERR_IO-1I/O callback returned an errorveloxfs_ERR_CORRUPT-2On-disk structure is inconsistentveloxfs_ERR_NOT_FOUND-3Path does not existveloxfs_ERR_EXISTS-4Path already existsveloxfs_ERR_NO_SPACE-5No free blocksveloxfs_ERR_INVALID-6Invalid argumentveloxfs_ERR_TOO_LARGE-7Operation exceeds limitsveloxfs_ERR_TOO_MANY_FILES-8Inode or directory table fullveloxfs_ERR_PERMISSION-9Permission denied
———
On-disk layout

RegionSizeSuperblock1 blockFATceil(block_count / 512) blocksJournal64 blocks (optional)Inode tableblock_count / 50 blocksDirectory tableblock_count / 100 blocksDataremainderBlock size is fixed at 4096 bytes. The FAT stores one uint64_t per block — 0 means free, 0xFFFFFFFFFFFFFFFF means end of chain, any other value is the index of the next block in the file.

———
Portability

The library requires C99 and the following standard headers: stdint.h, stddef.h, string.h, stdlib.h, stdio.h.

time.h is included automatically for the default timestamp implementation, but it is not required if you override the timestamp source (see below).

The FUSE adapter requires Linux and libfuse 2.x (FUSE_USE_VERSION 26).

There are no other dependencies.

Systems without a real-time clock

All timestamp calls go through a single overridable macro. If your platform has no RTC or no time() function (bare-metal, RTOS, WASM, etc.), define veloxfs_TIME() before including the header:

// No clock — store 0 for all timestamps#defineveloxfs_TIME() 0 // Custom clock source#defineveloxfs_TIME() my_rtc_get_unix_seconds()If veloxfs_TIME is not defined, it defaults to time(NULL) and time.h is included automatically.

———
Multi-platform Support (Needs One Minor Fix ⚠️) : Should be fixed now!

License

Public domain or MIT, your choice.