No description
  • C 68.9%
  • Python 16.9%
  • HTML 12.8%
  • Makefile 0.9%
  • Lua 0.2%
  • Other 0.2%
Find a file
2026-02-19 20:02:42 -08:00
data initial commit 2025-10-24 18:53:49 -07:00
littlefs-2.11.2 initial commit 2025-10-24 18:53:49 -07:00
lua-5.4.8 initial commit 2025-10-24 18:53:49 -07:00
flash.c make read test better by reading smaller chunks from the files 2026-01-11 00:04:10 -08:00
flash.h license added to sources 2025-11-29 07:16:59 -08:00
gendata.sh generated test files, allow multiple files in one block, fixed one-off error in delete 2025-10-27 20:33:02 -07:00
lfs initial commit 2025-10-24 18:53:49 -07:00
LICENSE Initial commit 2025-10-24 17:47:03 -07:00
littlefs.c directory operation added, bugfix with filetype reading 2026-02-01 20:38:27 -08:00
lua initial commit 2025-10-24 18:53:49 -07:00
Makefile make read test better by reading smaller chunks from the files 2026-01-11 00:04:10 -08:00
README.md Document zerofs_dir_next function in README 2026-02-01 20:44:47 -08:00
test.h license added to sources 2025-11-29 07:16:59 -08:00
test1.lua directory operation added, bugfix with filetype reading 2026-02-01 20:38:27 -08:00
test2.lua directory operation added, bugfix with filetype reading 2026-02-01 20:38:27 -08:00
testfilesizes.lua littlefs visualization improved for long tests, test modified to remove files even if disk is not full yet, added some additional test files 2025-11-02 11:14:13 -08:00
zerofs.c directory operation added, bugfix with filetype reading 2026-02-01 20:38:27 -08:00
zerofs.h do not increment global pos on read error 2026-02-19 20:02:42 -08:00

zerofs

zerofs is a dual-flash based embedded filesystem for devices where reads and writes happen in separate phases. Its made for systems that dont behave like general-purpose computers — for example, a sensor that occasionally logs data but spends most of its time reading back those files.

zerofs optimized exactly for this specific usage pattern. No directories, no journaling, no heap allocations, no power-failure recovery. Just deterministic, low-memory file access with full flash utilization. Data flash sectors contains no administrative data, just the payload. The superblock contains every metadata which besides in a separate flash area.

NOTE: Zerofs should be used only for battery powered devices when the power failure is predictable.


Why

Most embedded filesystems provide the "usual" general filesystem API: they sacrifice RAM, flash, and CPU time to support every scenario. zerofs is a specialist. It focuses on devices with distinct read/write phases, delivering:

  • Minimal RAM usage
    • less than 200 bytes in READ mode
    • ~1K in WRITE mode
  • Predictable behavior
  • Simplified flash management
  • Close to 100% flash utilization

Ideal for battery-backed systems and devices where you know the exact access pattern.


What

file purpose
zerofs.h the filesystem itself
flash.h flash simulation header
flash.c flash simulation implementation
test.h test related constants and definitions
zerofs.c lua test runner for zerofs backend
littlefs.c lua test runner for LittleFS backend
test1.lua lua test script
test2.lua lua stress test

Features

  • ~1 KB RAM usage total
  • No recursion, no heap
  • Flat file structure (no directories)
  • Distinct READ and WRITE modes
  • Write buffer (~1 KB) only needed during WRITE mode
  • Nearly 100% flash utilization
  • Dual flash design (e.g. MCU flash for metadata + external flash for data)
  • Header-only implementation
  • Background erase support
  • Generic flash interface layer
  • Designed for battery-backed environments

Integration

zerofs is header-only. Just define the implementation macro before including it:

#define ZEROFS_IMPLEMENTATION
#include "zerofs.h"

Include this once in your project (e.g. in a .c file). Everywhere else, just include "zerofs.h" normally.


Design Overview

zerofs separates read and write operations into exclusive modes.

  • WRITE mode: requires a temporary buffer (~1 KB) supplied by the user.
  • READ mode: buffer is not needed and can be reused for something else (like cache or DMA).

This mode separation allows deterministic memory usage and faster access with minimal overhead.


Demo

zerofs

asciicast

LittleFS (for comparison)

asciicast

Under the same workload, zerofs performs about half the flash operations of LittleFS. LittleFS provides more features and flexibility, but for certain patterns, zerofs offers far better RAM and speed efficiency.

fs time
littlefs 86772.4 ms
zerofs 44204.2 ms

Note1: measurements based on the timings of nRF52 series and the BY25Q32ES SPI flash IC.

Note2: LittleFS is configured to use similar amount of RAM what zerofs needs.


Test Harness

A flash simulation layer with integrated Lua scripting and TUI visualization.

Highlights

  • Flash access simulator with time measurement
  • Lua scripting for file operations
  • Compatible backend for both zerofs and LittleFS
  • Visual block map with file colors and inverse highlight for recent writes
  • Adjustable speed (<, >)
  • Step mode (s) and scrollable console
  • Script-controlled warnings and test failures
  • Optional log saving

Perfect for debugging, testing workloads, or benchmarking behavior.


Static Configuration Example

// Total flash size in KB
#define ZEROFS_FLASH_SIZE_KB (4096)

// Sector size of data flash (minimum erase unit)
#define ZEROFS_FLASH_SECTOR_SIZE (4096)

// Maximum number of files (checked by static asserts)
#define ZEROFS_MAX_NUMBER_OF_FILES (191)

// Sector size of superblock flash (usually MCU internal flash)
#define ZEROFS_SUPER_SECTOR_SIZE (4096)

// Superblock minimum write size in bytes (not enforced yet)
#define ZEROFS_SUPER_WRITE_GRANULARITY (4)

// Verify frequency, 0-off N-verify every Nth vrites
#define ZEROFS_VERIFY (0)

// Supported extensions (sorted, <255 total)
#define ZEROFS_EXTENSION_LIST \
    X("bin")                 \
    X("txt")                 \
    X("zip")

API Reference

All functions return 0 on success or a negative error code on failure.

Error Codes

#define ZEROFS_ERR_MAXFILES    (-2)  // Reached ZEROFS_MAX_NUMBER_OF_FILES
#define ZEROFS_ERR_NOTFOUND    (-3)  // File not found
#define ZEROFS_ERR_READMODE    (-4)  // Operation not allowed in READ mode
#define ZEROFS_ERR_NOSPACE     (-5)  // No space left on device
#define ZEROFS_ERR_OPEN        (-6)  // Failure during open
#define ZEROFS_ERR_ARG         (-7)  // Invalid argument
#define ZEROFS_ERR_WRITEMODE   (-8)  // Operation not allowed in WRITE mode
#define ZEROFS_ERR_OVERFLOW    (-9)  // Seek/write overflow
#define ZEROFS_ERR_BADSECTOR  (-10)  // Bad sector detected
#define ZEROFS_ERR_INVALIDFP  (-12)  // Invalid file descriptor structure

Initialization

int zerofs_init(struct zerofs *zfs, uint8_t verify, const struct zerofs_flash_access *fls_acc);

Parameters:

Name Description
zfs Filesystem instance structure to be initialized
verify Write verification rate. 0 = none, N = verify every Nth write
fls_acc Flash access callbacks and configuration

struct zerofs_flash_access

struct zerofs_flash_access {
    int (*fls_write)(void *ud, uint32_t addr, const uint8_t *data, uint32_t len);
    int (*fls_read)(void *ud, uint32_t addr, uint8_t *data, uint32_t len);
    int (*fls_erase)(void *ud, uint32_t addr, uint32_t len);
    uint8_t *superblock_banks;
    void *data_ud;
    void *super_ud;
};
Field Description
fls_write Function pointer to write bytes to flash
fls_read Function pointer to read bytes from flash
fls_erase Function pointer to erase sectors
superblock_banks Pointer to a memory-mapped flash region used for the superblock (metadata). Reads are done directly from memory. Writes still go through fls_write.
If no memory-mapped flash is available, this must point to a RAM buffer large enough to hold the superblock (~8 KB). This is less efficient in RAM usage, but supported.
data_ud User data pointer passed to data flash callbacks
super_ud User data pointer passed to superblock flash callbacks

Mode Management

int zerofs_is_readonly_mode(struct zerofs *zfs);

Returns nonzero if the filesystem is currently in READ mode.

int zerofs_readonly_mode(struct zerofs *zfs, uint8_t *sector_map);

Switches between READ and WRITE mode. If sector_map is NULL, enters READ mode. If non-NULL, enters WRITE mode using sector_map as a temporary buffer. The buffer size must be (ZEROFS_FLASH_SIZE_KB * 1024) / ZEROFS_FLASH_SECTOR_SIZE.


File Operations

int zerofs_format(struct zerofs *zfs);

Erases all files and resets the filesystem.

^⎚-⎚^

int zerofs_open(struct zerofs *zfs, struct zerofs_file *fp, const char *name);

Opens a file for reading (READ mode only).

int zerofs_create(struct zerofs *zfs, struct zerofs_file *fp, const char *name);

Creates and opens a file for writing (WRITE mode only).

int zerofs_append(struct zerofs *zfs, struct zerofs_file *fp, const char *name);

Opens an existing file for appending (WRITE mode only).

int zerofs_close(struct zerofs_file *fp);

Closes a file. For read-only files, this is effectively a no-op.

^⎚-⎚^

int zerofs_read(struct zerofs_file *fp, uint8_t *buf, uint32_t len);

Reads up to len bytes from a file opened for reading.

int zerofs_write(struct zerofs_file *fp, uint8_t *buf, uint32_t len);

Writes up to len bytes to a file opened for writing.

^⎚-⎚^

int zerofs_seek(struct zerofs_file *fp, int32_t pos);

Moves the read pointer within a file. Negative offsets are relative to the end of the file. Seeking is not supported during write mode.

^⎚-⎚^

int zerofs_dir_next(struct zerofs *zfs, struct zerofs_dirent *de);

Reads the directory. Use a zero filled zerofs_dirent for the first file. It will fills the provided zerofs_dirent struct with the next file data and returns non-zero when no more files in the filesystem.

int zerofs_delete(struct zerofs *zfs, const char *name);

Deletes a file by name.

uint32_t zerofs_file_len(struct zerofs *zfs);

Returns the length of the file. (macro)


Background Maintenance

int zerofs_background_erase(struct zerofs *zfs);

Performs background flash erases while in READ mode. Does not block reads, but must complete before switching to WRITE mode. The underlying flash driver is expected to handle the background flash operation if supported by the chip.

Third-party components

LittleFS v2.11.2 and Lua v5.4.8 are included here to make sure build would succeed.