Driver Interface
FsDriver and the four structural types it is built from — the whole shape a driver has to have.
import { S_IFDIR, S_IFMT, S_IFREG } from "mountx";
import type { DirentLike, FileHandleLike, FsDriver, StatsLike } from "mountx";Prose version, with a complete driver you can run: Writing a driver.
#FsDriver
Three required methods; everything else optional, and missing means the capability is absent.
interface FsDriver {
readonly capabilities?: FsCapabilities;
readonly mountx?: MountxExtensions;
// required
stat(path: string): Promise<StatsLike>;
readdir(path: string, options: { withFileTypes: true }): Promise<DirentLike[]>;
open(path: string, flags?: string | number, mode?: number): Promise<FileHandleLike>;
// optional
lstat?(path: string): Promise<StatsLike>;
statfs?(path: string): Promise<StatsFsLike>;
mkdir?(path: string, options?: MkdirOptions): Promise<string | undefined>;
rmdir?(path: string): Promise<void>;
unlink?(path: string): Promise<void>;
rename?(oldPath: string, newPath: string): Promise<void>;
link?(existingPath: string, newPath: string): Promise<void>;
symlink?(target: string, path: string, type?: string | null): Promise<void>;
readlink?(path: string): Promise<string>;
chmod?(path: string, mode: number): Promise<void>;
chown?(path: string, uid: number, gid: number): Promise<void>;
lchown?(path: string, uid: number, gid: number): Promise<void>;
truncate?(path: string, length?: number): Promise<void>;
utimes?(path: string, atime: TimeLike, mtime: TimeLike): Promise<void>;
lutimes?(path: string, atime: TimeLike, mtime: TimeLike): Promise<void>;
}Every path is absolute, POSIX-style and normalized before your driver sees it.
FullFsDriver is the same with every optional method required — the memory and node-fs drivers satisfy it, and so does node:fs/promises. FsDriverMethod is the union of the optional method names.
The two readonly members are on their own page: Capabilities.
#Structural types
All four are the smallest shapes the transports need, so Node's own Stats, StatsFs, Dirent and FileHandle satisfy them unmodified.
#StatsLike
interface StatsLike {
dev: number;
ino: number;
mode: number; // S_IFMT type bits | permission bits
nlink: number;
uid: number;
gid: number;
rdev: number;
size: number;
blksize: number;
blocks: number;
atimeMs: number;
mtimeMs: number;
ctimeMs: number;
birthtimeMs: number;
isFile(): boolean;
isDirectory(): boolean;
isSymbolicLink(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
}#DirentLike
{ name: string; parentPath?: string } plus the same seven type predicates.
#StatsFsLike
{ type, bsize, blocks, bfree, bavail, files, ffree } — for statfs(2) and df.
#FileHandleLike
interface FileHandleLike {
readonly fd?: number;
read(
buffer: Uint8Array,
offset?: number | null,
length?: number | null,
position?: number | null,
): Promise<{ bytesRead: number; buffer: Uint8Array }>;
write(
buffer: Uint8Array,
offset?: number | null,
length?: number | null,
position?: number | null,
): Promise<{ bytesWritten: number; buffer: Uint8Array }>;
stat(): Promise<StatsLike>;
truncate(length?: number): Promise<void>;
close(): Promise<void>;
sync?(): Promise<void>; // absent = nothing to flush
datasync?(): Promise<void>;
}Whether that handle is real per-open state is the handles capability, one of the two that cannot be inferred.
#File-type constants
S_IFMT, S_IFREG, S_IFDIR, S_IFLNK, S_IFBLK, S_IFCHR, S_IFIFO, S_IFSOCK — the POSIX mode bits, for building and interrogating StatsLike.mode.
import { S_IFDIR, S_IFMT } from "mountx";
const isDirectory = (mode: number) => (mode & S_IFMT) === S_IFDIR;#Next
- Capabilities — what a driver declares, and what is inferred from the methods above.
- Errors — what to throw out of them.