Files v0.1.0
StdIn
pub const StdIn: int32 = 0;
The descriptor a process reads its input from, unless something reassigned it.
StdOut
pub const StdOut: int32 = 1;
The descriptor a process writes its output to.
StdErr
pub const StdErr: int32 = 2;
The descriptor a process writes its diagnostics to, which is separate so it survives a redirected output.
Read
pub func Read(
fd: FileDescriptor,
buffer: *var opaque,
count: uint
) -> int64
Reads up to count bytes from fd into buffer.
fd and count are read by value; buffer is borrowed and written. Returns the number of bytes actually read,
zero at end of file, or a negative error number.
A count smaller than count is ordinary and is not an end of file: a pipe, a terminal, or a signal can each cut a
read short. Only zero means the source has ended.
buffer must be writable for count bytes. The kernel checks the address and reports EFAULT rather than
faulting, but it does not check the length against anything the caller knows.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
buffer | *var opaque | receives the bytes |
count | uint | how many bytes to ask for |
Returns: the bytes read, zero at end of file, or a negative error number
Write
pub func Write(
fd: FileDescriptor,
buffer: *opaque,
count: uint
) -> int64
Writes up to count bytes from buffer to fd.
fd and count are read by value; buffer is borrowed and read. Returns the number of bytes actually written,
or a negative error number.
A count smaller than count is ordinary, and the rest has to be written by calling again from where this
stopped. Writing to a pipe whose reader has closed raises SIGPIPE before this can report EPIPE.
buffer must be readable for count bytes.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
buffer | *opaque | the bytes to write |
count | uint | how many bytes to offer |
Returns: the bytes written, or a negative error number
Close
pub func Close(fd: FileDescriptor) -> int64
Closes fd and releases what the kernel held for it.
fd is read by value. Returns zero, or a negative error number.
A failure does not mean the descriptor is still open: on Linux it is released whatever this reports, so retrying
a failed close can close a descriptor another thread has since opened under the same number.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
Returns: zero, or a negative error number
AtFdCwd
pub const AtFdCwd: int32 = -100;
AT_FDCWD: resolve a relative path against the current directory rather than a descriptor.
The value every *at call takes when the caller means an ordinary path. It is -100 rather than -1 so that a
stray -1 from a failed open cannot be mistaken for it.
OpenReadOnly
pub const OpenReadOnly: int32 = 0;
O_RDONLY: open for reading only.
OpenWriteOnly
pub const OpenWriteOnly: int32 = 1;
O_WRONLY: open for writing only.
OpenReadWrite
pub const OpenReadWrite: int32 = 2;
O_RDWR: open for both reading and writing.
OpenCreate
pub const OpenCreate: int32 = 64;
O_CREAT: create the file when it does not exist, which is when the mode argument is read.
OpenExclusive
pub const OpenExclusive: int32 = 128;
O_EXCL: with OpenCreate, fail rather than open a file that already exists.
The pair is what makes creating a file an atomic claim on the name.
OpenTruncate
pub const OpenTruncate: int32 = 512;
O_TRUNC: truncate the file to nothing when opening it for writing.
OpenAppend
pub const OpenAppend: int32 = 1024;
O_APPEND: every write goes to the end, atomically with respect to other appenders.
OpenNonBlocking
pub const OpenNonBlocking: int32 = 2048;
O_NONBLOCK: reads and writes report EAGAIN rather than waiting.
OpenCloseOnExec
pub const OpenCloseOnExec: int32 = 524288;
O_CLOEXEC: close this descriptor automatically when the process executes a new program.
Worth setting on nearly everything: without it a descriptor leaks into every child, which is both a resource and
a confidentiality problem.
OpenDirectory
// x86-64
pub const OpenDirectory: int32 = 65536;
// AArch64
pub const OpenDirectory: int32 = 16384;
O_DIRECTORY: fail unless the target is a directory.
x86-64 kept the number it had before the generic table was drawn up. On AArch64 this same bit means
O_DIRECT instead, so a directory opened with the wrong number fails with EINVAL rather than opening.
SeekSet
pub const SeekSet: int32 = 0;
SEEK_SET: measure the new offset from the start of the file.
SeekCurrent
pub const SeekCurrent: int32 = 1;
SEEK_CUR: measure the new offset from the current one.
SeekEnd
pub const SeekEnd: int32 = 2;
SEEK_END: measure the new offset from the end of the file.
OpenAt
pub func OpenAt(
directoryFd: FileDescriptor,
path: *char8,
flags: int32,
mode: FileMode
) -> int64
Opens path relative to directoryFd and returns a descriptor, or a negative error number.
directoryFd is a descriptor for the directory a relative path is resolved against, or AtFdCwd for the current
one; an absolute path ignores it. path is borrowed and must be null-terminated. flags is one of the three
access modes combined with whatever else applies. mode is the permission bits a newly created file gets, and is
read only when OpenCreate is set.
This is the only open the package offers, because it is the only one AArch64 has.
path must be non-null and terminated. The mode is masked by the process umask, which this cannot see.
Parameters
| Name | Type | Description |
|---|---|---|
directoryFd | FileDescriptor | the directory path is relative to, or AtFdCwd for an ordinary path |
path | *char8 | the path to open, as a null-terminated byte string |
flags | int32 | the access mode and the open flags, combined with | |
mode | FileMode | the permission bits for a file this creates, ignored otherwise |
Returns: the new descriptor, or a negative error number
Lseek
pub func Lseek(
fd: FileDescriptor,
offset: FileOffset,
whence: int32
) -> int64
Moves the file offset of fd and returns where it ended up, or a negative error number.
offset is measured from whichever origin whence names. Returns the resulting absolute offset.
Seeking past the end is allowed and creates a hole when something is later written there. A pipe or socket has no
offset to move and reports ESPIPE.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
offset | FileOffset | how far to move, interpreted according to whence |
whence | int32 | SeekSet, SeekCurrent or SeekEnd |
Returns: the resulting offset from the start, or a negative error number
FstatAt
pub func FstatAt(
directoryFd: FileDescriptor,
path: *char8,
statBuffer: *var opaque,
flags: int32
) -> int64
Fills statBuffer with what the kernel knows about the file path names.
The kernel's own name for this call is newfstatat, which SysNewFstatAt keeps; the wrapper is spelled the way
macOS and FreeBSD spell theirs, so one name reaches the call on all three systems.
statBuffer must be writable for the whole of the architecture's struct stat, whose layout this package
does not model: 144 bytes on x86-64 and 128 on AArch64, with the fields at different offsets in each.
Parameters
| Name | Type | Description |
|---|---|---|
directoryFd | FileDescriptor | the directory path is relative to, or AtFdCwd for an ordinary path |
path | *char8 | the path to describe, as a null-terminated byte string |
statBuffer | *var opaque | receives the architecture's struct stat |
flags | int32 | zero to follow a symbolic link at the end of the path, or SymlinkNoFollow to describe the link |
Returns: zero, or a negative error number
FchmodAt
pub func FchmodAt(
directoryFd: FileDescriptor,
path: *char8,
mode: FileMode,
flags: int32
) -> int64
Sets the permission bits of the file path names.
directoryFd is AtFdCwd for an ordinary path. Returns zero, or a negative error number. Linux does not
support SymlinkNoFollow here and reports EOPNOTSUPP for it: a symbolic link's own bits mean nothing.
Parameters
| Name | Type | Description |
|---|---|---|
directoryFd | FileDescriptor | the directory path is relative to, or AtFdCwd for an ordinary path |
path | *char8 | the path whose bits are set |
mode | FileMode | the permission bits to set |
flags | int32 | zero, or SymlinkNoFollow where the system supports it |
Returns: zero, or a negative error number
UtimensAt
pub func UtimensAt(
directoryFd: FileDescriptor,
path: *char8,
times: *opaque,
flags: int32
) -> int64
Sets the access and modification times of the file path names.
times is borrowed and holds two timespec values — access first, then modification — each a whole-second
count and a nanosecond fraction, both 8 bytes. A null times sets both to now. flags may carry
SymlinkNoFollow. Returns zero, or a negative error number.
Parameters
| Name | Type | Description |
|---|---|---|
directoryFd | FileDescriptor | the directory path is relative to, or AtFdCwd for an ordinary path |
path | *char8 | the path whose times are set |
times | *opaque | two timespec values, or null for now |
flags | int32 | zero to follow a final symbolic link, or SymlinkNoFollow |
Returns: zero, or a negative error number
Fsync
pub func Fsync(fd: FileDescriptor) -> int64
Flushes everything written to fd through to the storage device.
Returns zero, or a negative error number. Returning only once the device has acknowledged the write is the whole
point: without it, data a successful Write reported may still be lost to a power failure.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
Returns: zero, or a negative error number
Ftruncate
pub func Ftruncate(
fd: FileDescriptor,
length: FileOffset
) -> int64
Sets the length of the file behind fd to length.
Returns zero, or a negative error number. Growing a file this way creates a hole rather than allocating, so a
later write into it can still fail with ENOSPC. Shrinking discards what was past the new end.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
length | FileOffset | the size the file should have afterwards |
Returns: zero, or a negative error number
Fstat
pub func Fstat(
fd: FileDescriptor,
statBuffer: *var opaque
) -> int64
Fills statBuffer with what the kernel knows about the file behind fd.
statBuffer is borrowed and written with the kernel's struct stat, whose layout this package does not model:
it differs by architecture, and reading it needs a declaration that says which. Returns zero, or a negative error
number.
statBuffer must be writable for the whole of the architecture's struct stat, which is 144 bytes on x86-64 and
128 on AArch64. Nothing here checks that.
Parameters
| Name | Type | Description |
|---|---|---|
fd | FileDescriptor | an open descriptor |
statBuffer | *var opaque | receives the architecture's struct stat |
Returns: zero, or a negative error number
Dup3
pub func Dup3(
oldFd: FileDescriptor,
newFd: FileDescriptor,
flags: int32
) -> int64
Makes newFd a copy of oldFd, closing whatever newFd was.
flags may carry OpenCloseOnExec, which is the reason this exists rather than dup2: setting it afterwards
leaves a window in which another thread can execute a new program and leak the descriptor. Returns newFd, or a
negative error number.
Duplicating a descriptor onto itself reports EINVAL here, where dup2 returned it unchanged.
Parameters
| Name | Type | Description |
|---|---|---|
oldFd | FileDescriptor | the descriptor to duplicate |
newFd | FileDescriptor | the number the duplicate should have |
flags | int32 | zero, or OpenCloseOnExec for the new descriptor |
Returns: newFd, or a negative error number
Pipe2
pub func Pipe2(
descriptors: *var int32,
flags: int32
) -> int64
Creates a pipe and writes its two descriptors into descriptors.
descriptors is borrowed and receives the reading end at index zero and the writing end at index one. flags
may carry OpenCloseOnExec and OpenNonBlocking. Returns zero, or a negative error number.
descriptors must be writable for two int32 values.
Parameters
| Name | Type | Description |
|---|---|---|
descriptors | *var int32 | receives the read end at index zero and the write end at index one |
flags | int32 | zero, or OpenCloseOnExec for both ends |
Returns: zero, or a negative error number