This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
make # build module/fs.so + mount/redis-fs-mount + rfs
make module # build module/fs.so only
make mount # build mount/redis-fs-mount only
make cli # build rfs only
make clean # remove compiled artifacts
# CLI lifecycle helper:
./rfs setup
./rfs up
./rfs down
./rfs status
./rfs migrate <directory>Load into Redis for manual testing:
redis-server --loadmodule ./module/fs.so
# or at runtime:
redis-cli MODULE LOAD $(pwd)/module/fs.soThere is no automated test suite. Testing is manual via redis-cli.
Redis-FS is a native Redis module (C, -std=c11) that registers a custom data type (fsObject) and an FS.* command family. One Redis key = one complete filesystem.
- fsObject: Top-level container holding a
RedisModuleDictmapping absolute path strings to inodes, plus aggregate counters (file_count, dir_count, symlink_count, total_data_size). - fsInode: Union-typed node — file (inline content + 256-byte trigram bloom filter), directory (children basename array), or symlink (target string). Every inode carries POSIX metadata (mode, uid, gid, ctime/mtime/atime).
- Storage is flat: paths like
/etc/nginx/nginx.confare keys in a single dict, not a tree. Directories track only child basenames. This gives O(1) path lookups.
| File | Purpose |
|---|---|
module/fs.c |
All command handlers, RDB persistence, type registration, bloom filter logic |
module/fs.h |
Inode/object struct definitions, type constants |
module/path.c |
Path normalization, parent/basename/join, full glob matching (*, ?, [a-z], [!x], \ escaping) |
module/path.h |
Path utility declarations |
module/redismodule.h |
Redis module API (vendored header) |
- Auto-create / auto-delete: First write to a key creates it with root
/; deleting everything removes the key. - Symlink resolution (
fsResolvePath): follows up to 40 levels, supports absolute and relative targets. - Bloom filters for GREP: each file inode has a 256-byte bloom filter built from lowercased trigrams.
FS.GREPskips files whose bloom filter proves the literal portion of the pattern cannot match. - Binary detection in GREP: files with NUL bytes in the first 8KB report "Binary file matches" instead of content.
- Parent auto-creation (
fsEnsureParents): write commands likeFS.ECHOandFS.MKDIR PARENTSrecursively create missing ancestor directories. - FS.ECHO APPEND flag:
FS.ECHO key path content APPENDappends instead of overwriting, matching the shellecho >>pattern.FS.APPENDis retained as a backward-compatible alias. - RDB format version 0: serializes all inodes with path/type/metadata/payload; bloom filters are rebuilt on load, not persisted.
Every FS.* command handler follows the same pattern:
- Call
fsGetObject()to open the key and get/create thefsObject - Normalize the path with
fsNormalizePath() - Look up the inode in the dict
- Perform the operation, replicate if write (
RedisModule_ReplicateVerbatim()) - For writes, call
fsMaybeDeleteKey()if content was removed