zena:fs

zena
import {…} from 'zena:fs';

Filesystem Standard Library - WASI Preview 1 Implementation

Provides file and directory operations using wasi_snapshot_preview1 interfaces. See docs/design/filesystem.md for the full design.

WASI Capability-Based Security

WASI uses a capability-based security model for filesystem access. Unlike traditional operating systems where processes can access any file path they have permission to, WASI programs have NO filesystem access by default.

Access is granted through "preopened directories" - directories that the host environment explicitly passes to the WASM module at startup. The module can only access files within these preopened directories.

For example, when running with wasmtime:

text
wasmtime run --dir /data::/data --dir /tmp::/tmp myprogram.wasm

This grants access to /data and /tmp on the host, mapped to the same paths in the guest. Without these flags, the program cannot access the filesystem at all.

The high-level functions (readFile, writeFile, etc.) use the first preopened directory as the root. For more control, use getPreopens() to access all available directories, or work with Descriptor objects directly.

Classes

FsError

zena
class FsError extends Error
Extends Error
Constructors
zena
new(errno: i32, message: String)
#
Properties
zena
code: FsErrorCode
#
zena
errno: i32
#
2 inherited members
From Error
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

Descriptor

zena
class Descriptor

A handle for an open file or directory.

Descriptors are obtained either from getPreopens() (for preopened directories) or by opening files/directories relative to an existing descriptor using openAt() or createAt().

In WASI's capability model, a Descriptor acts as a capability token - you can only access files that are reachable from a Descriptor you already have.

Always call close() when done to release the underlying resource.

text
let root = getRootDir();
let file = root.openAt('data.txt', DescriptorFlags.Read);
let content = file.readString();
file.close();
Constructors
zena
new(fd: i32)
#
Properties
zena
fd: i32 { get; }
#
Methods
zena
readAllBytes(): ByteArray
#
zena
readString(): String
#
zena
writeBytes(data: ByteArray): void
#
zena
writeString(data: String): void
#
zena
openAt(path: String, flags: DescriptorFlags): Descriptor
#
zena
createAt(path: String): Descriptor
#
zena
stat(): FileStat
#
zena
statAt(path: String): FileStat
#
zena
readDir(): Array<DirEntry>
#
zena
mkdirAt(path: String): void
#
zena
unlinkAt(path: String): void
#
zena
rmdirAt(path: String): void
#
zena
close(): void
#

Enums

FsErrorCode

zena
enum FsErrorCode
Members
zena
Success
#
zena
Access
#
zena
BadDescriptor
#
zena
Exist
#
zena
NotFound
#
zena
IsDirectory
#
zena
NotDirectory
#
zena
NotEmpty
#
zena
ReadOnly
#
zena
InvalidSeek
#
zena
Io
#
zena
InvalidArgument
#
zena
NameTooLong
#
zena
NoSpace
#
zena
NotPermitted
#

FileType

zena
enum FileType
Members
zena
Unknown
#
zena
BlockDevice
#
zena
CharacterDevice
#
zena
Directory
#
zena
RegularFile
#
zena
Socket
#

OpenFlags

zena
enum OpenFlags
Members
zena
None
#
zena
Create
#
zena
Directory
#
zena
Exclusive
#
zena
Truncate
#

DescriptorFlags

zena
enum DescriptorFlags
Members
zena
Read
#
zena
Write
#
zena
ReadWrite
#
zena
MutateDirectory
#

Type aliases

FileStat

zena
type FileStat = {fileType: FileType, size: i64}

DirEntry

zena
type DirEntry = {name: String, fileType: FileType}

Functions

getPreopens

zena
function getPreopens(): Array<(Descriptor, String)>

Returns all preopened directories granted to this WASM module.

Preopened directories are the ONLY filesystem locations this program can access. They are granted by the host environment at startup (e.g., via wasmtime's --dir flag).

Each entry is a tuple of [Descriptor, path] where:

  • Descriptor is a handle for filesystem operations within that directory
  • path is the guest path (e.g., "/tmp", "/data", or "." for current dir)

Returns an empty array if no directories were preopened (the program has no filesystem access).

text
let preopens = getPreopens();
for (let (dir, path) in preopens) {
  console.log('Access granted to: ' + path);
}

getRootDir

zena
function getRootDir(): Descriptor

Returns the first preopened directory, used as the "root" for high-level file operations.

This is typically the current working directory (".") or the first --dir flag passed to the WASI runtime.

Throws FsError

if no directories were preopened.

readFile

zena
function readFile(path: String): String

readFileBytes

zena
function readFileBytes(path: String): ByteArray

Reads the entire contents of a file as raw bytes.

The path is relative to the first preopened directory.

Throws FsError

if the file doesn't exist or cannot be read.

writeFile

zena
function writeFile(path: String, content: String): void

Writes a string to a file as UTF-8, creating or truncating the file.

The path is relative to the first preopened directory.

Throws FsError

if the file cannot be written (e.g., permission denied, directory doesn't exist, or read-only filesystem).

writeFileBytes

zena
function writeFileBytes(path: String, content: ByteArray): void

Writes raw bytes to a file, creating or truncating the file.

The path is relative to the first preopened directory.

Throws FsError

if the file cannot be written.

listDir

zena
function listDir(path: String): Array<DirEntry>

Lists the contents of a directory.

The path is relative to the first preopened directory. Use "." to list the root preopened directory itself.

Returns

Array of directory entries with name and file type.

Throws FsError

if the path doesn't exist or is not a directory.

exists

zena
function exists(path: String): boolean

Checks if a path exists (file or directory).

The path is relative to the first preopened directory.

Returns

true if the path exists, false otherwise.

isFile

zena
function isFile(path: String): boolean

Checks if a path is a regular file.

Returns

true if the path exists and is a file, false otherwise.

isDirectory

zena
function isDirectory(path: String): boolean

Checks if a path is a directory.

Returns

true if the path exists and is a directory, false otherwise.

mkdir

zena
function mkdir(path: String): void

Creates a directory.

The path is relative to the first preopened directory. Parent directories must already exist.

Throws FsError

if the directory cannot be created.

zena
function unlink(path: String): void

Deletes a file.

The path is relative to the first preopened directory.

Throws FsError

if the file doesn't exist or cannot be deleted.

rmdir

zena
function rmdir(path: String): void

Deletes an empty directory.

The path is relative to the first preopened directory. The directory must be empty.

Throws FsError

if the directory doesn't exist, is not empty, or cannot be deleted.