Temporary resources
For ordinary scratch storage with with support, prefer
std.tempfile. These lower-level owners provide rooted staging
and explicit publication.
temporary_file(&root) -> Result[TempFile, IoError] creates an unnamed
O_TMPFILE inode in the root’s filesystem, mode 0600 restricted by umask.
Its public stream: std.io.FileStream is readable and writable; seek back
to read what was written. publish(&name) adds a
name with atomic no-replace linkat; existing files, directories and dangling
links are refused. A successful publication can occur once. It leaves the
stream open; close() reports close errors, and ordinary drop closes it.
Closing/dropping before publication releases the unnamed inode without an
unlink-by-name race. After publication the name persists.
import std.fs as fs
import std.io
import std.path as path
def main() -> Result[(), AllocError | IoError | std.io.StreamError | std.io.Partial]:
current = path.from_text(".")?
root = fs.root(¤t)?
mut staged = fs.temporary_file(&root)?
std.io.write_all(&mut staged.stream, &b"complete contents")?
staged.stream.sync()?
staged.publish(&path.from_text("config.txt")?)?
staged.close()?
print(read_text("config.txt")?)?
Ok(())
complete contents
remove_published(&name) -> Result[(), FsError] explicitly removes a published
name after comparing it with the still-open stream’s device and inode. A missing
name succeeds; a different regular file returns FsError.Replaced, and symlinks
are refused. The stream remains open. Publication is still allowed only once.
As with directory cleanup, identity checking and removal are not atomic against
hostile concurrent renames. This operation supports std.tempfile ownership.
Publication uses /proc/self/fd so unprivileged users need no special
capability. The filesystem must support O_TMPFILE, and procfs must be
available for publication. Unsupported filesystems and unavailable procfs
produce IoError (normally a native System code); there is no named-file
fallback. A successful publish is not a durability promise; call
stream.sync() before publishing if needed. Directory durability is not
provided here. Temporary creation itself copies no metadata.
copy_file and copy_tree can preserve ordinary permission
bits and access/modification times before completing their copy operation.
temporary_dir_named(&root, &name) exclusively creates a 0700 directory and
returns Result[TempDir, FsError]. A collision is reported and never removed.
temporary_dir(&root, &prefix, attempts: Positive[i64]) appends 32 lowercase
hex digits from 16 OS secret bytes, retrying only EEXIST up to attempts. An
attempts above 1024 traps. Prefixes are at most 200 bytes without slash/NUL; no UTF-8 conversion is imposed.
Entropy errors are reported without weakening the name source.
TempDir.name() and root() lend its name and directory handle. Explicit
cleanup() removes only an empty directory and reports errors. It is
idempotent after success. keep() disarms cleanup; the directory remains.
The destructor attempts the same empty-only cleanup and ignores errors.
This low-level destructor never recursively deletes contents. Fatal traps/process termination
do not unwind; explicit cleanup is required when its success matters.
Cleanup’s native name conversion can allocate: if allocation remains exhausted
during drop, even an empty directory can remain. File/directory handles still
close without allocation. Creation reserves names and owner storage before
mkdir, so allocation failure during construction leaves no directory behind.
cleanup_tree(max_entries: Positive[i64], max_depth: Positive[i64], &cancel) -> Result[(), FsError] is an
explicit recursive alternative, using the bounded deletion
budgets. It checks identity before traversing the held directory and again
before removing its entry. Successful cleanup disarms the owner. Failure can
leave partial cleanup and leaves it armed. std.tempfile.TemporaryDirectory
uses this operation for its best-effort destructor.
Temporary directories require a parent whose entries other actors do not
rename while the owner is live. Cleanup compares the held directory’s device
and inode to the named directory and reports FsError.Replaced for a changed
identity. A missing name or symlink is an I/O error. This catches replacements
already visible at the check; Linux has no compare-inode-and-unlink syscall,
so the check and rmdir are not atomic against a concurrent rename. Empty
replacement directories can still be removed by a racing actor. Nonempty
replacements are never traversed by the empty-only cleanup. A child-open failure
after mkdir attempts empty-only rollback under the same parent-trust contract.
Temporary names/owners and copies are allocated fallibly. A temporary file holds its file descriptor and a duplicate root descriptor. A temporary directory holds its directory and parent descriptors plus its name bytes. See root rules and bounded operations.