Module sys/perm

sys/perm
Stability: unstable — the POSIX permission model this exposes does not exist on Windows, and the shim there does not say so. `fchown`/`chownat` return `-ENOSYS` unless asked to change nothing; `chmodat` only honours the WRITE bit, silently dropping the rest of the mode; `access` drops `X_OK`, so an executability check degenerates into an existence check; and only `AT_FDCWD` is accepted for the `dirfd`. Freezing needs a decision about what this module promises on an ACL platform — a permission type that maps honestly (Rust's `Permissions` with its `readonly` flag is the precedent) or a loud refusal, but not a quiet partial success. — stable modules only change additively; this one may still change.

File permissions, ownership and access checks — the raw syscall boundary.

chmod, chown and access, in their fd and *at forms. All are synchronous on every platform, so they return i32 directly rather than an IoFuture. No public std module changes permissions yet (std/fs/metadata only reads the mode); tests/sys/perm.test.yo is the only caller in this tree.

Returns 0 on success and a negative errno on failure, throughout.

Stability

unstable — the POSIX permission model this exposes does not exist on Windows, and the shim there does not say so. fchown/chownat return -ENOSYS unless asked to change nothing; chmodat only honours the WRITE bit, silently dropping the rest of the mode; access drops X_OK, so an executability check degenerates into an existence check; and only AT_FDCWD is accepted for the dirfd. Freezing needs a decision about what this module promises on an ACL platform — a permission type that maps honestly (Rust's Permissions with its readonly flag is the precedent) or a loud refusal, but not a quiet partial success.

Functions

fchmod function
fn(fd : i32, mode : u32) -> i32

Set the permission bits of an OPEN descriptor — POSIX fchmod(2). mode is the usual octal word (0o644), and only the permission and set-id bits are used: the file-type bits of a Statx.mode() must be masked off before passing it back in. Returns 0 on success, a negative errno on failure.

Windows has no fchmod: the runtime resolves the handle back to a path with GetFinalPathNameByHandleW and calls _wchmod, which only reads the owner-write bit — so 0o600 and 0o777 are the same request there, and 0o444 is the only way to say anything at all (read-only).

Parameters

NameTypeNotes
fdi32
modeu32

Returns: i32

chmodat function
fn(dirfd : i32, path : *u8, mode : u32, flags : i32) -> i32

Set the permission bits of path, resolved relative to dirfd — POSIX fchmodat(2). Pass AT_FDCWD (from std/sys/constants) for the current directory, or an open directory descriptor. flags is 0 or AT_SYMLINK_NOFOLLOW. Returns 0 on success, a negative errno on failure.

macOS routes AT_FDCWD to plain chmod(2); Windows accepts ONLY AT_FDCWD (-EINVAL for a real directory descriptor), ignores flags, and has the same write-bit-only _wchmod limitation as fchmod.

Parameters

NameTypeNotes
dirfdi32
path*u8
modeu32
flagsi32

Returns: i32

fchown function
fn(fd : i32, uid : u32, gid : u32) -> i32

Set the owner and group of an OPEN descriptor — POSIX fchown(2). Pass u32(0xFFFFFFFF) (POSIX (uid_t)-1) for either id to leave it unchanged. Returns 0 on success, a negative errno on failure; changing the owner generally needs privilege, so -EPERM is the ordinary outcome for an unprivileged process.

Windows has no numeric uid/gid model: the shim returns -ENOSYS unless BOTH ids are the "no change" sentinel, in which case it succeeds without doing anything.

Parameters

NameTypeNotes
fdi32
uidu32
gidu32

Returns: i32

chownat function
fn(dirfd : i32, path : *u8, uid : u32, gid : u32, flags : i32) -> i32

Set the owner and group of path, resolved relative to dirfd — POSIX fchownat(2). AT_FDCWD for the current directory; flags is 0 or AT_SYMLINK_NOFOLLOW, and with it set the SYMLINK's ownership changes rather than the target's. Same 0xFFFFFFFF no-change sentinel and same Windows -ENOSYS as fchown.

macOS routes AT_FDCWD to chown(2) — or lchown(2) when AT_SYMLINK_NOFOLLOW is set — rather than to fchownat.

Parameters

NameTypeNotes
dirfdi32
path*u8
uidu32
gidu32
flagsi32

Returns: i32

access function
fn(dirfd : i32, path : *u8, mode : i32) -> i32

Ask whether path (relative to dirfd) is accessible in the ways mode names — POSIX faccessat(2), or access(2) when dirfd is AT_FDCWD. mode is F_OK (exists) or an OR of R_OK, W_OK and X_OK, all from std/sys/constants. Returns 0 when the whole request is satisfied, otherwise a negative errno — -ENOENT for a missing path, -EACCES when it exists but the access is denied.

The check uses the process's REAL uid and gid, not the effective ones, and it is inherently a race: the answer can be stale by the time you act on it. Prefer attempting the operation and handling its error, exactly as Rust does (it deliberately has no access wrapper).

On Windows only AT_FDCWD is accepted (-EINVAL otherwise) and X_OK is STRIPPED before calling _waccess, because Windows has no execute permission bit — so access(.., X_OK) there answers the existence question instead of the one you asked.

Parameters

NameTypeNotes
dirfdi32
path*u8
modei32

Returns: i32