std.fs

Files and directories. Gated on fs:read and fs:write for package code; root code has full authority.

import std.fs

fs.read("notes.txt")            # string
fs.read_bytes("logo.png")       # bytes
fs.write("out.txt", text)
fs.append("log.txt", line)

fs.exists(p)  fs.is_file(p)  fs.is_dir(p)
fs.list_dir(dir)                # names
fs.walk(dir)                    # recursive entries
fs.glob("src/**/*.ecko")

fs.mkdir(p)  fs.copy(a, b)  fs.rename(a, b)  fs.remove(p)

Text or bytes

read returns a string and errors on invalid UTF-8. read_bytes returns bytes and always works. Use read_bytes for anything that is not certainly text - the strict default is what stops a binary file from becoming a string full of replacement characters.

Paths

fs.join(a, b), fs.basename(p), fs.dirname(p), fs.extension(p) - and fs.path(...) for building one. Use these rather than concatenating with "/", so the code works on Windows too.

Walking and matching

list_dir is one level; walk recurses and yields entries with path and is_dir. glob takes a pattern with * and **, and fs.match(pattern, path) tests one path against a pattern.

for entry in fs.walk("src") {
    if not entry.is_dir and fs.extension(entry.path) == "ecko" { check(entry.path) }
}

Temporary files

dir = fs.temp_dir()
f = fs.temp_file()

temp_file gives a unique path in the system temporary directory. Nothing cleans up after you - remove what you create.

Errors

Everything raises { kind: "fs", path, message } on failure. The path field is there so a handler can report which file, which is the thing you always want and often lose:

try { data = fs.read(p) } catch (e) {
    match get(e, "kind") { "fs" => print("cannot read {e.path}") _ => error(e) }
}

Paths from untrusted input

A path built from user input can escape the directory you meant. ../../etc/passwd is a path. If a request names a file, validate it - or better, do not use fs for it at all: web.static resolves safely and is the right tool for serving files.

Capabilities help but are not a path sandbox: fs:read grants reading, not reading within a directory.