File Class
Static methods for file operations: reading, writing, glob patterns, and file metadata.
Filesystem jail and symlink defense
When the application is started with soli serve <dir>, every path passed to slurp / barf / File.* / mkdir_p / file_write_* is resolved relative to <dir> and rejected if it escapes that root (via absolute paths, .. segments, or symlinks pointing outside). A controller calling File.read(req["params"]["path"]) therefore can no longer reach /etc/passwd.
On Unix, every File.* open additionally passes O_NOFOLLOW, and metadata lookups go through symlink_metadata. A path that is a symlink therefore fails to open through File.* even when the target is itself in-jail — this defends against local TOCTOU swaps that would otherwise race a canonicalised path against an attacker-supplied symlink.
CLI invocations (soli run, the REPL, the test runner) do not install a jail, so command-line scripts keep full filesystem access. Code that genuinely needs to step outside the jail or follow symlinks deliberately (log shippers, backup scripts, cron-style maintenance jobs, tailing a symlinked log file) should use the parallel Trusted class — Trusted.read("/var/log/..."), Trusted.write(...), etc. Its API mirrors File exactly but skips both the jail check and the O_NOFOLLOW flag, making the unsafe access explicit at the call site so reviewers and grep can find it.
File.glob_recursive(pattern)
Match files using glob pattern (recursive).
files = File.glob_recursive("docs/**/*.md")
File.is_dir(path)
Check if path is a directory.
File.is_file(path)
Check if path is a file.
File.size(path)
Get file size in bytes.
File.modified(path)
Get file modification timestamp (Unix epoch in seconds).
time = File.modified("config.json")
File.copy(src, dest)
Copy file from source to destination.
File.rename(old, new)
Rename/move a file.
File.append(path, content)
Append content to file.