Module sys/perm
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
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
| Name | Type | Notes |
|---|---|---|
fd | i32 | |
mode | u32 |
Returns: 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
| Name | Type | Notes |
|---|---|---|
dirfd | i32 | |
path | *u8 | |
mode | u32 | |
flags | i32 |
Returns: 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
| Name | Type | Notes |
|---|---|---|
fd | i32 | |
uid | u32 | |
gid | u32 |
Returns: 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
| Name | Type | Notes |
|---|---|---|
dirfd | i32 | |
path | *u8 | |
uid | u32 | |
gid | u32 | |
flags | i32 |
Returns: 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
| Name | Type | Notes |
|---|---|---|
dirfd | i32 | |
path | *u8 | |
mode | i32 |
Returns: i32