Files
narratio/docs/internal/fileops.md

2.4 KiB

Internal: File Operations

internal/fileops owns the narrow mechanics for atomically visible replacement of one byte file. Callers keep ownership of serialization, validation, cancellation, and destination-directory policy.

Destination Paths

Ordinary workspace replacement uses standard operating-system path semantics. Callers with a root-scoped safety contract own that validation at their boundary.

Remote object acquisition is owned by its domain caller. The caller writes a sibling temporary file, validates the complete result, and passes that file to InstallSiblingTempFile only when it is ready to become canonical. Callers own remote object selection, validation, conflict handling, and temporary-file cleanup.

Directory bundles are not promoted by internal/fileops; extraction owns its validated Notarius bundle rename.

Cleanup Contract

RemoveAllUnderRoot accepts an explicit root and a proper descendant, opens that root with os.OpenRoot, and removes the normalized root-relative target with Root.RemoveAll. It rejects root, traversal, and out-of-root targets; a missing target is successful. RemoveFileUnderRoot additionally requires an existing leaf to be regular. Command and post-publish policy remains owned by internal/app.

Bounded Reads

ReadFileBounded opens a normal path and reads at most its caller-supplied limit. Credential mode policy and environment precedence remain owned by internal/app.

Replacement Contract

ReplaceFileAtomic requires an existing destination directory. It creates a sibling temporary file, writes the complete byte sequence, applies the caller-supplied mode, closes the file, runs an optional pre-rename check, and replaces the destination with a rename.

The pre-rename check is the last point at which a caller can cancel without installing a new destination. A failure before the rename leaves the old destination unchanged and removes the temporary file. Successful replacement provides atomic visibility; it makes no crash- or power-loss durability claim.

Replacement follows the operating system's same-filesystem rename semantics. If a platform cannot replace an existing destination, the operation returns an error and never removes the old file as an emulation step.

WriteFileAtomic and the copy helpers create the destination parent with the repository's workspace permissions. InstallSiblingTempFile requires the caller to provide an existing temporary file in the existing destination directory.