CtrlK
BlogDocsLog inGet started
Tessl Logo

rust-system-calls

Guides using bun_sys for system calls and file I/O in Rust. Use when implementing file operations, opening fds, or any syscall path instead of std::fs or libc.

70

Quality

85%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

System Calls & File I/O in Rust

Use bun_sys instead of std::fs or raw libc for cross-platform syscalls with proper error handling.

bun_sys::File (Preferred)

For most file operations, use the bun_sys::File wrapper. It owns the fd and closes on Drop.

use bun_sys::{File, Fd, O};

let file = File::openat(Fd::cwd(), b"path/to/file", O::RDONLY, 0)?;
let mut buf = vec![0u8; 4096];
let n = file.read_all(&mut buf)?;     // loops until EOF or full
// `file` closes on Drop.

Complete Example

use bun_sys::{File, Fd, O};

pub fn write_file(path: &[u8], data: &[u8]) -> Result<(), bun_sys::Error> {
    let file = File::openat(Fd::cwd(), path, O::WRONLY | O::CREAT | O::TRUNC, 0o664)?;
    file.write_all(data)?;
    Ok(())
}

Why bun_sys?

Aspectbun_sysstd::fs / libc
Return TypeMaybe<T> with rich Errorio::Error (lossy)
WindowsFull support with libuv fallbackIncomplete/POSIX-ish
Error Infoerrno, syscall tag, path, fderrno only
EINTRAutomatic retryManual handling
Paths&[u8] (WTF-8 safe)&Path (UTF-8 lossy)

Error Handling with Maybe

bun_sys functions return Maybe<T> = Result<T, bun_sys::Error>. Propagate with ?; convert to a JS exception via bun_sys_jsc::ErrorJsc::to_js:

use bun_sys_jsc::ErrorJsc;
use bun_sys::{File, Fd, O};

let file = match File::openat(Fd::cwd(), path, O::RDONLY, 0) {
    Ok(f) => f,
    Err(err) => return Ok(err.to_js(global)?),
};

bun_sys::Error carries errno, syscall: Tag, and path: Box<[u8]>. To branch on errno:

match bun_sys::unlink(path) {
    Ok(()) => {}
    Err(e) if e.errno() == bun_c::ENOENT => {} // already gone
    Err(e) => return Err(e),
}

Key Types and Functions

  • Fd (bun_core::Fd) — cross-platform file descriptor. Fd::cwd(), Fd::stdin()/stdout()/stderr(), fd.close().
  • File::open(path: &ZStr, flags, mode) / File::openat(dir: Fd, path: &[u8], flags, mode) / File::make_open(...) (creates parent dirs) / File::create(dir, path, truncate)
  • file.read(buf) / read_all(buf) / read_to_end() / read_to_end_small() / write(buf) / write_all(buf)
  • bun_sys::open, read, write, pread, pwrite, stat, fstat, lstat, mkdir, unlink, rename, symlink, chmod — free fns over Fd
  • Open flags: bun_sys::O::RDONLY, O::WRONLY | O::CREAT | O::TRUNC, etc.

Path Buffers

Use bun_paths for joining/normalization and the path-buffer pool to avoid 64 KB stack allocations on Windows:

use bun_paths::{path_buffer_pool, resolve_path::{self, platform}};

let mut buf = path_buffer_pool::get();
let joined = resolve_path::join_string_buf::<platform::Auto>(&mut *buf, &[dir, name]);
let file = File::openat(Fd::cwd(), joined, O::RDONLY, 0)?;

Common Mistakes

  • Don't .unwrap() a bun_sys result that user input or the OS can cause to fail at runtime — return the error.
  • Don't use std::fs::File — it loses the syscall tag and path needed for Node-compatible error objects.
  • Don't allocate PathBuffer on the stack in hot paths — use path_buffer_pool::get().
  • Don't forget Drop alone closes a File — never file.fd().close() while the File is still live (double close).

See src/CLAUDE.md for the full bun_core/bun_sys reference.

Repository
oven-sh/bun
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.