xfs

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package xfs provides filesystem primitives for Nexss workspaces.

Three layers, two threat models:

  • WriteFile / WriteFileAtomic(path, ...) — trusted path, no validation. Use only for paths your code builds from constants (config dirs, cache roots, temp dirs). WriteFile is a thin wrapper over os.WriteFile; WriteFileAtomic is temp+fsync+rename.

  • Rel(p) — string-level validation of an untrusted path. Fast, typed errors. Rejects absolute paths, "..", ":", NUL, control chars, trailing dots, Windows reserved device names.

  • Root — kernel-enforced containment. Opens a directory handle via os.OpenRoot; every path goes through Rel first, then through the kernel, which refuses symlink escapes and TOCTOU races that Rel alone cannot see. Any path derived from user input, HTTP, config, or plugin manifests MUST go through Root.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Rel

func Rel(p string) (string, error)

Rel validates a caller-supplied path and returns its cleaned form.

func WriteFile

func WriteFile(path string, data []byte, perm os.FileMode) error

WriteFile writes data to path non-atomically. A crash mid-write leaves path truncated or partially written.

The caller is responsible for supplying a trusted path. WriteFile performs no validation — for caller-supplied (untrusted) paths, open an xfs.Root and use Root.WriteFile instead.

func WriteFileAtomic

func WriteFileAtomic(path string, data []byte, perm os.FileMode) error

WriteFileAtomic writes data to path atomically. A crash mid-write leaves path either at its previous content or at the new content; never in between.

The caller is responsible for supplying a trusted path. WriteFileAtomic performs no validation — for caller-supplied (untrusted) paths, open an xfs.Root and use Root.WriteFileAtomic instead.

On POSIX the rename is atomic within a filesystem. On Windows it is atomic within a volume and retries up to 5 times on transient sharing violations (a common interference on Windows hosts).

data is fsync'd before the rename. The parent directory is fsync'd after on POSIX; Windows does not expose directory fsync and the rename is atomic but not durable across power loss.

Types

type Root

type Root struct {
	// contains filtered or unexported fields
}

Root confines file operations to a trusted directory. Every path argument is validated by Rel (fast, typed errors) and then opened through os.Root (kernel-level containment: symlinks cannot escape, TOCTOU on the resolved path is closed).

Rule for the codebase: any path derived from user input, HTTP requests, workspace config, or plugin manifests MUST go through Root. xfs.WriteFile is only for paths your code builds from trusted constants.

func OpenRoot

func OpenRoot(dir string) (*Root, error)

OpenRoot opens dir as a confined root. The caller must Close it.

func (*Root) Chmod

func (r *Root) Chmod(p string, mode os.FileMode) error

Chmod changes the file mode.

func (*Root) Chtimes

func (r *Root) Chtimes(p string, atime, mtime time.Time) error

Chtimes updates access and modification times.

NOTE: On Unix, Chmod/Chown/Chtimes are documented as racy — the stdlib may operate on a symlink if the target changes mid-call. Prefer writing through WriteFileAtomic over mutating in place.

func (*Root) Close

func (r *Root) Close() error

Close releases the root handle.

func (*Root) Create

func (r *Root) Create(p string) (*os.File, error)

Create creates or truncates a file.

func (*Root) FS

func (r *Root) FS() fs.FS

FS returns an fs.FS view rooted at r's directory. Useful with fs.WalkDir, template.ParseFS, io/fs.ReadDir, etc.

func (*Root) Lstat

func (r *Root) Lstat(p string) (os.FileInfo, error)

Lstat is Stat without following the final symlink.

func (*Root) Mkdir

func (r *Root) Mkdir(p string, perm os.FileMode) error

Mkdir creates a single directory.

func (*Root) MkdirAll

func (r *Root) MkdirAll(p string, perm os.FileMode) error

MkdirAll creates a directory tree.

func (*Root) Name

func (r *Root) Name() string

Name returns the root's directory name.

func (*Root) Open

func (r *Root) Open(p string) (*os.File, error)

Open opens a caller-supplied path for reading.

func (*Root) OpenFile

func (r *Root) OpenFile(p string, flag int, perm os.FileMode) (*os.File, error)

OpenFile opens with explicit flags. The path is validated by Rel; the kernel-level os.Root rejects symlink escapes even when O_CREATE is combined with a pre-existing symlink at the target.

func (*Root) ReadFile

func (r *Root) ReadFile(p string) ([]byte, error)

ReadFile reads a caller-supplied path.

func (*Root) Remove

func (r *Root) Remove(p string) error

Remove removes a file or empty directory.

func (*Root) RemoveAll

func (r *Root) RemoveAll(p string) error

RemoveAll removes a tree.

func (*Root) Rename

func (r *Root) Rename(oldp, newp string) error

Rename moves oldp to newp, both validated by Rel.

func (*Root) Stat

func (r *Root) Stat(p string) (os.FileInfo, error)

Stat returns FileInfo for a caller-supplied path.

func (*Root) WriteFile

func (r *Root) WriteFile(p string, data []byte, perm os.FileMode) error

WriteFile writes data to p, confined to the root. Non-atomic: a crash mid-write leaves p truncated or partially written. Use only when the file is reconstructible (cache, generated artifact, spill file). For anything a reader will later trust (config, state, user data), use WriteFileAtomic.

func (*Root) WriteFileAtomic

func (r *Root) WriteFileAtomic(p string, data []byte, perm os.FileMode) error

WriteFileAtomic writes data to p atomically: a crash mid-write leaves p either at its previous content or at the new content, never in between. Costs one extra file create + fsync + rename.

The temp file is created inside the root with O_EXCL so a pre-created file (attacker-controlled symlink, sibling race) cannot hijack the write. Symlink escapes are blocked by os.Root.

On Windows, the final rename retries up to 5 times to survive transient sharing violations (AV scanners, indexers) — mirroring the behavior of xfs.WriteFileAtomic.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL