ESC
Type to search...
S
Soli Docs

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.read(path)

Read file contents as string.

content = File.read("config.json")
File.write(path, content)

Write content to file.

File.write("output.txt", "Hello!")
File.exists(path)

Check if file exists.

if File.exists("config.json") {
  # do something
}
File.delete(path)

Delete a file.

File.delete("old.txt")
File.glob(pattern)

Match files using glob pattern (non-recursive).

files = File.glob("docs/*.md")
File.glob_recursive(pattern)

Match files using glob pattern (recursive).

files = File.glob_recursive("docs/**/*.md")
File.lines(path)

Read file as array of lines.

lines = File.lines("data.txt")
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.