Files v0.1.0

Source
Opening, reading, writing and inspecting files through descriptors.

StdIn

pub const StdIn: int32 = 0;

The descriptor a process reads its input from, unless something reassigned it.

Source

StdOut

pub const StdOut: int32 = 1;

The descriptor a process writes its output to.

Source

StdErr

pub const StdErr: int32 = 2;

The descriptor a process writes its diagnostics to, which is separate so it survives a redirected output.

Source

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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran open descriptor
buffer*var opaquereceives the bytes
countuinthow 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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran open descriptor
buffer*opaquethe bytes to write
countuinthow 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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran 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.

Source

OpenReadOnly

pub const OpenReadOnly: int32 = 0;

O_RDONLY: open for reading only.

Source

OpenWriteOnly

pub const OpenWriteOnly: int32 = 1;

O_WRONLY: open for writing only.

Source

OpenReadWrite

pub const OpenReadWrite: int32 = 2;

O_RDWR: open for both reading and writing.

Source

OpenCreate

pub const OpenCreate: int32 = 64;

O_CREAT: create the file when it does not exist, which is when the mode argument is read.

Source

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.

Source

OpenTruncate

pub const OpenTruncate: int32 = 512;

O_TRUNC: truncate the file to nothing when opening it for writing.

Source

OpenAppend

pub const OpenAppend: int32 = 1024;

O_APPEND: every write goes to the end, atomically with respect to other appenders.

Source

OpenNonBlocking

pub const OpenNonBlocking: int32 = 2048;

O_NONBLOCK: reads and writes report EAGAIN rather than waiting.

Source

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.

Source

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.

Source

SeekSet

pub const SeekSet: int32 = 0;

SEEK_SET: measure the new offset from the start of the file.

Source

SeekCurrent

pub const SeekCurrent: int32 = 1;

SEEK_CUR: measure the new offset from the current one.

Source

SeekEnd

pub const SeekEnd: int32 = 2;

SEEK_END: measure the new offset from the end of the file.

Source

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.

Source

Parameters

NameTypeDescription
directoryFdFileDescriptorthe directory path is relative to, or AtFdCwd for an ordinary path
path*char8the path to open, as a null-terminated byte string
flagsint32the access mode and the open flags, combined with |
modeFileModethe 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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran open descriptor
offsetFileOffsethow far to move, interpreted according to whence
whenceint32SeekSet, 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.

Source

Parameters

NameTypeDescription
directoryFdFileDescriptorthe directory path is relative to, or AtFdCwd for an ordinary path
path*char8the path to describe, as a null-terminated byte string
statBuffer*var opaquereceives the architecture's struct stat
flagsint32zero 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.

Source

Parameters

NameTypeDescription
directoryFdFileDescriptorthe directory path is relative to, or AtFdCwd for an ordinary path
path*char8the path whose bits are set
modeFileModethe permission bits to set
flagsint32zero, 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.

Source

Parameters

NameTypeDescription
directoryFdFileDescriptorthe directory path is relative to, or AtFdCwd for an ordinary path
path*char8the path whose times are set
times*opaquetwo timespec values, or null for now
flagsint32zero 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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran 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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran open descriptor
lengthFileOffsetthe 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.

Source

Parameters

NameTypeDescription
fdFileDescriptoran open descriptor
statBuffer*var opaquereceives 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.

Source

Parameters

NameTypeDescription
oldFdFileDescriptorthe descriptor to duplicate
newFdFileDescriptorthe number the duplicate should have
flagsint32zero, 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.

Source

Parameters

NameTypeDescription
descriptors*var int32receives the read end at index zero and the write end at index one
flagsint32zero, or OpenCloseOnExec for both ends

Returns: zero, or a negative error number