The filesystem API provides file descriptor management, mount operations, path resolution, and filesystem abstraction layers.
File Descriptors
FD Structure
The fd structure represents an open file, socket, device, or other I/O resource.
struct fd {
atomic_uint refcount; // Reference count
unsigned flags; // File flags (O_RDWR, O_NONBLOCK, etc.)
mode_t_ type; // File type (S_IFMT part only)
const struct fd_ops *ops; // Operations table
struct list poll_fds; // Poll/select tracking
lock_t poll_lock; // Poll lock
unsigned long offset; // Current file position
// Type-specific data
union {
struct { struct tty *tty; } tty;
struct { struct poll *poll; } epollfd;
struct { uint64_t val; } eventfd;
struct { struct timer *timer; uint64_t expirations; } timerfd;
struct {
int domain, type, protocol;
char unix_name[108];
struct fd *unix_peer;
// ...
} socket;
void *data;
};
// Filesystem data
struct mount *mount; // Associated mount point
int real_fd; // Host OS file descriptor
DIR *dir; // Directory stream
struct inode_data *inode; // Inode data
ino_t fake_inode; // Fake inode number
struct statbuf stat; // File stat information
lock_t lock; // General lock
cond_t cond; // Condition variable
};
FD Operations
struct fd_ops {
ssize_t (*read)(struct fd *fd, void *buf, size_t bufsize);
ssize_t (*write)(struct fd *fd, const void *buf, size_t bufsize);
ssize_t (*pread)(struct fd *fd, void *buf, size_t bufsize, off_t off);
ssize_t (*pwrite)(struct fd *fd, const void *buf, size_t bufsize, off_t off);
off_t_ (*lseek)(struct fd *fd, off_t_ off, int whence);
int (*readdir)(struct fd *fd, struct dir_entry *entry);
unsigned long (*telldir)(struct fd *fd);
void (*seekdir)(struct fd *fd, unsigned long ptr);
int (*mmap)(struct fd *fd, struct mem *mem, page_t start, pages_t pages, off_t offset, int prot, int flags);
int (*poll)(struct fd *fd);
ssize_t (*ioctl_size)(int cmd);
int (*ioctl)(struct fd *fd, int cmd, void *arg);
int (*fsync)(struct fd *fd);
int (*close)(struct fd *fd);
int (*getflags)(struct fd *fd);
int (*setflags)(struct fd *fd, dword_t arg);
};
FD Management Functions
struct fd *fd_create(const struct fd_ops *ops);
struct fd *fd_retain(struct fd *fd);
int fd_close(struct fd *fd);
int fd_getflags(struct fd *fd);
int fd_setflags(struct fd *fd, int flags);
Creates a new file descriptor with the given operations table
Increments reference count and returns the fd
Decrements reference count and frees if zero. Returns 0 on success.
Example:
// Create a new file descriptor
struct fd *fd = fd_create(&my_fd_ops);
fd->flags = O_RDWR_;
fd->type = S_IFREG;
// Use the fd
fd_retain(fd);
// Close when done
fd_close(fd);
Directory Entry
struct dir_entry {
qword_t inode; // Inode number
char name[NAME_MAX + 1]; // Filename (NAME_MAX = 255)
};
File Descriptor Table
The fdtable manages all open file descriptors for a process.
struct fdtable {
atomic_uint refcount; // Reference count
unsigned size; // Table size
struct fd **files; // Array of fd pointers
bits_t *cloexec; // Close-on-exec flags
lock_t lock; // Table lock
};
FD Table Functions
struct fdtable *fdtable_new(int size);
void fdtable_release(struct fdtable *table);
struct fdtable *fdtable_copy(struct fdtable *table);
void fdtable_free(struct fdtable *table);
void fdtable_do_cloexec(struct fdtable *table);
struct fd *fdtable_get(struct fdtable *table, fd_t f);
struct fd *f_get(fd_t f);
fd_t f_install(struct fd *fd, int flags);
int f_close(fd_t f);
Creates a new fd table with specified size
Creates a copy of the fd table (for fork)
Closes all fds with close-on-exec flag set
Gets fd from current task’s fd table
Installs fd into current task’s fd table. Returns fd number or error.
Example:
// Create fd table for new process
struct fdtable *table = fdtable_new(256);
// Install a file descriptor
struct fd *fd = fd_create(&realfs_fdops);
fd_t fd_num = f_install(fd, O_CLOEXEC_);
if (fd_num < 0) {
// Error
}
// Get fd from current process
struct fd *my_fd = f_get(fd_num);
// Close fd
f_close(fd_num);
Mount Operations
The mount system manages filesystem mount points.
Mount Structure
Each mounted filesystem is represented by a mount structure:
struct mount {
const char *point; // Mount point path
const char *source; // Source device/path
const char *info; // Mount options
int flags; // Mount flags (MS_READONLY_, etc.)
const struct fs_ops *fs; // Filesystem operations
void *data; // Filesystem-specific data
unsigned refcount; // Reference count
struct list mounts; // Mount list link
};
Mount Functions
struct mount *mount_find(char *path);
void mount_retain(struct mount *mount);
void mount_release(struct mount *mount);
Finds the mount point for a given path. Path must be normalized.
Increments mount reference count
Decrements mount reference count
int do_mount(const struct fs_ops *fs, const char *source,
const char *point, const char *info, int flags);
int mount_remove(struct mount *mount);
int do_umount(const char *point);
Mounts a filesystem at the specified mount point. Returns 0 on success.
Unmounts filesystem at the given path. Returns 0 on success or -EBUSY.
Example:
#include "fs/real.h"
// Mount a real filesystem
int err = do_mount(&realfs, "/path/to/source", "/mnt", "", 0);
if (err < 0) {
return err;
}
// Use the mounted filesystem
char path[] = "/mnt/file.txt";
struct mount *mount = mount_find(path);
// ... use mount ...
mount_release(mount);
// Unmount when done
do_umount("/mnt");
Path Resolution
Path resolution converts user paths to normalized absolute paths.
Path Normalization
int path_normalize(const char *at_path, const char *path, char *out, int flags);
Base path for relative paths, or NULL for current directory
Path to normalize (can be relative or absolute)
Output buffer for normalized path (must be MAX_PATH bytes)
Flags controlling symlink following (N_SYMLINK_FOLLOW or N_SYMLINK_NOFOLLOW)
Returns 0 on success, negative error code on failure
Normalization features:
- Resolves
. and .. components
- Converts relative to absolute paths
- Follows symbolic links (if N_SYMLINK_FOLLOW)
- Handles mount point boundaries
- Detects symlink loops (max 5 levels)
Example:
char normalized[MAX_PATH];
int err = path_normalize("/home/user", "../file.txt",
normalized, N_SYMLINK_FOLLOW);
if (err < 0) {
return err;
}
// normalized now contains "/home/file.txt"
Fake Filesystem Database
The fake filesystem uses SQLite to store metadata for files.
Database Structure
struct fakefs_db {
sqlite3 *db; // SQLite database handle
struct {
sqlite3_stmt *begin_deferred;
sqlite3_stmt *begin_immediate;
sqlite3_stmt *commit;
sqlite3_stmt *rollback;
sqlite3_stmt *path_get_inode;
sqlite3_stmt *path_read_stat;
sqlite3_stmt *path_create_stat;
sqlite3_stmt *path_create_path;
sqlite3_stmt *inode_read_stat;
sqlite3_stmt *inode_write_stat;
sqlite3_stmt *path_link;
sqlite3_stmt *path_unlink;
sqlite3_stmt *path_rename;
sqlite3_stmt *path_from_inode;
sqlite3_stmt *try_cleanup_inode;
} stmt; // Prepared statements
sqlite3_mutex *lock; // Database lock
};
Stat Structure
struct ish_stat {
uint32_t mode; // File mode and permissions
uint32_t uid; // Owner user ID
uint32_t gid; // Owner group ID
uint32_t rdev; // Device ID (for special files)
};
Database Initialization
int fake_db_init(struct fakefs_db *fs, const char *db_path, int root_fd);
int fake_db_deinit(struct fakefs_db *fs);
Initializes the fake filesystem database. Returns 0 on success.
Path to SQLite database file
File descriptor of the root directory
Transaction Management
void db_begin_read(struct fakefs_db *fs);
void db_begin_write(struct fakefs_db *fs);
void db_commit(struct fakefs_db *fs);
void db_rollback(struct fakefs_db *fs);
Begins a read transaction (deferred lock)
Begins a write transaction (immediate lock)
Example:
struct fakefs_db db;
fake_db_init(&db, "/path/to/meta.db", root_fd);
// Read transaction
db_begin_read(&db);
inode_t ino = path_get_inode(&db, "/home/user/file.txt");
db_commit(&db);
// Write transaction
db_begin_write(&db);
struct ish_stat stat = { .mode = 0644, .uid = 1000, .gid = 1000 };
inode_t new_ino = path_create(&db, "/tmp/newfile", &stat);
db_commit(&db);
Path Operations
inode_t path_get_inode(struct fakefs_db *fs, const char *path);
bool path_read_stat(struct fakefs_db *fs, const char *path, struct ish_stat *stat, uint64_t *inode);
inode_t path_create(struct fakefs_db *fs, const char *path, struct ish_stat *stat);
Gets inode number for path. Returns 0 if not found.
Reads file stat for path. Returns true if found.
Creates new file at path. Returns new inode number.
Inode Operations
bool inode_read_stat_if_exist(struct fakefs_db *fs, inode_t inode, struct ish_stat *stat);
void inode_read_stat_or_die(struct fakefs_db *fs, inode_t inode, struct ish_stat *stat);
void inode_write_stat(struct fakefs_db *fs, inode_t inode, struct ish_stat *stat);
Reads inode stat. Returns false if inode doesn’t exist.
Reads inode stat. Aborts if inode doesn’t exist.
Updates inode stat in database
Link Operations
void path_link(struct fakefs_db *fs, const char *src, const char *dst);
inode_t path_unlink(struct fakefs_db *fs, const char *path);
void path_rename(struct fakefs_db *fs, const char *src, const char *dst);
Creates hard link from src to dst
Removes path. Returns inode number of unlinked file.
Renames/moves file from src to dst
Example:
db_begin_write(&db);
// Create hard link
path_link(&db, "/home/user/original", "/home/user/link");
// Rename file
path_rename(&db, "/tmp/old", "/tmp/new");
// Delete file
inode_t ino = path_unlink(&db, "/tmp/deleteme");
db_commit(&db);
Filesystem Operations Table
Each filesystem type implements the fs_ops structure:
struct fs_ops {
int (*mount)(struct mount *mount);
int (*umount)(struct mount *mount);
int (*stat)(struct mount *mount, const char *path, struct statbuf *stat);
int (*fstat)(struct fd *fd, struct statbuf *stat);
int (*open)(struct mount *mount, const char *path, int flags, int mode, struct fd *fd);
int (*readlink)(struct mount *mount, const char *path, char *buf, size_t size);
int (*link)(struct mount *mount, const char *src, const char *dst);
int (*unlink)(struct mount *mount, const char *path);
int (*rmdir)(struct mount *mount, const char *path);
int (*rename)(struct mount *mount, const char *src, const char *dst);
int (*mkdir)(struct mount *mount, const char *path, mode_t mode);
int (*symlink)(struct mount *mount, const char *target, const char *link);
};
Built-in filesystems:
realfs - Real host filesystem
procfs - Process information filesystem (/proc)
devptsfs - Pseudoterminal device filesystem
tmpfs - Temporary in-memory filesystem
Register custom filesystem:
void fs_register(const struct fs_ops *fs);
static const struct fs_ops myfs = {
.mount = myfs_mount,
.open = myfs_open,
.stat = myfs_stat,
// ... other operations ...
};
fs_register(&myfs);