silk.platform.native.file.
POSIX file and directory operations on host paths and descriptors, for native providers and runtimes that need the full file model of the system.
When to use#
Use NativeFile to build a runtime or a provider that must expose the file operations of the
host as they are: open flags and modes, positioned reads and writes, complete status records,
links, owners, times, and directory entries. Application code that only reads and writes files
uses the FileSystem effect from silk.system.filesystem instead. That effect's native provider,
silk.platform.native.filesystem, keeps each path inside a root directory; NativeFile does not.
Details#
A path is bytes, as the system takes it. A relative path starts at the working directory of the
process, and symbolic links resolve as the system resolves them. A path is copied with a final
zero byte into a buffer of PATH_LIMIT bytes, so a longer path fails with the code for a name
that is too long, and a path that contains a zero byte fails with the code for an argument that
is not valid.
Each operation is one system call, or a short fixed sequence for NativeFile.copy. A call
that a signal interrupts is made again. The operations block the calling thread; run them on a
worker thread when the caller must stay responsive.
FileStatus holds every field of the system record. On Linux it comes from statx, so the
birth time is set when the file system records it, and is zero when it does not. On Darwin it
comes from stat, which always has the birth time.
The open flags and mode bits that the system uses are constants of this module, such as
OPEN_CREATE. Their values differ between targets, so do not write the numbers.
Errors#
Each operation fails with NativeFileError: the NativeFileOperation and the errno value.
Gotchas#
A descriptor from
NativeFile.openbelongs to the caller. Close it withNativeFile.close. Nothing closes it on a drop.NativeFile.changeModeof a symbolic link itself, withfollowLinksfalse, fails on Linux, which cannot change the mode of a link.The module is empty on targets other than Darwin on x86_64 or aarch64, and Linux with GNU libc on x86_64 or aarch64.
Examples#
Write, read back, and inspect a file#
import silk.collections.slice { Slice }
import silk.core.effect { Effect }
import silk.core.option { Option }
import silk.core.result { Result }
import silk.platform.native.file {
NativeFile,
NativeFileError,
OPEN_CREATE,
OPEN_EXCLUSIVE,
OPEN_READ_WRITE,
TYPE_FILE,
TYPE_MASK,
}
effect fn program() -> i32 ! NativeFileError {
let mut directory: [u8; 64] = [0; 64]
let length = run NativeFile.makeTemporaryDirectory(b"/tmp/silk-file-XXXXXX", &mut directory)
let mut path: [u8; 72] = [0; 72]
let mut index: usize = 0
while index < length {
path[index] = directory[index]
index = index + 1
}
let name = b"/data"
let mut offset: usize = 0
while offset < name.length {
path[length + offset] = name[offset]
offset = offset + 1
}
let file = Slice.view<u8>(&path, 0, length + name.length)
let fd = run NativeFile.open(file, OPEN_READ_WRITE | OPEN_CREATE | OPEN_EXCLUSIVE, 420)
let written = run NativeFile.write(fd, b"hello", Option<u64>.none())
// A positioned read does not move the file offset.
let mut buffer: [u8; 3] = [0, 0, 0]
let read = run NativeFile.read(fd, &mut buffer, Option<u64>.some(2))
let status = run NativeFile.statusOf(fd)
run NativeFile.close(fd)
run NativeFile.remove(file)
run NativeFile.removeDirectory(Slice.view<u8>(&directory, 0, length))
if written != 5 || read != 3 || buffer[0] != 108 || status.size != 5 {
return 1
}
if (status.mode & TYPE_MASK) != TYPE_FILE {
return 1
}
return 0
}
pub effect fn main() -> i32 {
return match run Effect.result(program()) {
Result<i32, NativeFileError>.Success { value } => value
Result<i32, NativeFileError>.Failure { .. } => 1
}
}Import as NativeFile with import silk.platform.native.file { NativeFile }.
Public declarations: 36.
PATH_LIMIT#
pub const PATH_LIMIT: usizeThe number of bytes that a path and its final zero byte may use.
NativeFileOperation#
pub enum NativeFileOperationThe operation of NativeFile that failed.
Open#
OpenClose#
CloseRead#
ReadNativeFile.read and NativeFile.readScatter.
Write#
WriteNativeFile.write and NativeFile.writeGather.
Status#
StatusNativeFile.status and NativeFile.statusOf.
Truncate#
TruncateNativeFile.truncate and NativeFile.truncateOf.
Synchronize#
SynchronizeSetTimes#
SetTimesNativeFile.setTimes and NativeFile.setTimesOf.
ChangeMode#
ChangeModeNativeFile.changeMode and NativeFile.changeModeOf.
ChangeOwner#
ChangeOwnerNativeFile.changeOwner and NativeFile.changeOwnerOf.
Link#
LinkSymbolicLink#
SymbolicLinkReadLink#
ReadLinkRealPath#
RealPathRename#
RenameRemove#
RemoveRemoveDirectory#
RemoveDirectoryMakeDirectory#
MakeDirectoryMakeTemporaryDirectory#
MakeTemporaryDirectoryNativeFile.makeTemporaryDirectory.
Copy#
CopyAccess#
AccessVolumeStatus#
VolumeStatusOpenDirectory#
OpenDirectoryReadDirectory#
ReadDirectoryCloseDirectory#
CloseDirectoryNativeFileError#
pub struct NativeFileErrorA failed NativeFile operation: which one, and the native error code.
Details#
code is the errno value of the failed system call, such as 2 (ENOENT) for a path that does
not exist.
Field operation#
pub operation: NativeFileOperationThe operation that failed.
Field code#
pub code: i32The native error code.
Timestamp#
pub struct TimestampA point in time: seconds and nanoseconds since 1970-01-01 00:00:00 UTC.
Field seconds#
pub seconds: i64Whole seconds. Negative for a time before 1970.
Field nanoseconds#
pub nanoseconds: u32Nanoseconds after seconds, from 0 through 999999999.
Implementation Copy for Timestamp#
impl Copy for TimestampFileStatus#
pub struct FileStatusThe status record of a file, as the system keeps it.
Details#
mode holds the type bits (TYPE_MASK) and the permission bits. born is zero when the file
system does not record a birth time. flags and generation are zero on Linux.
Field device#
pub device: u64The device that holds the file.
Field inode#
pub inode: u64The inode number.
Field mode#
pub mode: u32The type and permission bits.
Field links#
pub links: u64The number of hard links.
Field user#
pub user: u32The user id of the owner.
Field group#
pub group: u32The group id of the owner.
Field specialDevice#
pub specialDevice: u64The device that the file is, for a device file.
Field size#
pub size: u64The size in bytes.
Field blockSize#
pub blockSize: u64The preferred block size for transfers.
Field blocks#
pub blocks: u64The number of 512-byte blocks that the file uses.
Field flags#
pub flags: u32The user flags of the file, on Darwin.
Field generation#
pub generation: u32The generation number of the file, on Darwin.
Field accessed#
pub accessed: TimestampThe time of the last read.
Field modified#
pub modified: TimestampThe time of the last change of the data.
Field changed#
pub changed: TimestampThe time of the last change of the status.
Field born#
pub born: TimestampThe time of creation, or zero when the file system does not record it.
Implementation Copy for FileStatus#
impl Copy for FileStatusVolumeStatus#
pub struct VolumeStatusThe status of the file system that holds a path.
Field kind#
pub kind: u64The file system type number.
Field blockSize#
pub blockSize: u64The block size in bytes.
Field blocks#
pub blocks: u64The total number of blocks.
Field freeBlocks#
pub freeBlocks: u64The number of free blocks.
Field availableBlocks#
pub availableBlocks: u64The number of free blocks that a user without privileges can use.
Field files#
pub files: u64The total number of file nodes.
Field freeFiles#
pub freeFiles: u64The number of free file nodes.
Implementation Copy for VolumeStatus#
impl Copy for VolumeStatusEntryKind#
pub enum EntryKindThe type of a directory entry, as the directory reports it.
Unknown#
UnknownThe file system did not report the type. Get it with NativeFile.status.
File#
FileA regular file.
Directory#
DirectoryA directory.
SymbolicLink#
SymbolicLinkA symbolic link.
Fifo#
FifoA named pipe.
Socket#
SocketA socket.
CharacterDevice#
CharacterDeviceA character device.
BlockDevice#
BlockDeviceA block device.
DirectoryEntry#
pub struct DirectoryEntryThe name and the type of one directory entry, from Directory.next.
Field length#
pub length: usizeThe number of name bytes written to the start of the output buffer.
Field kind#
pub kind: EntryKindThe type of the entry.
CopyMethod#
pub enum CopyMethodHow NativeFile.copy makes the copy.
Bytes#
BytesCopy the bytes.
CloneOrBytes#
CloneOrBytesShare the data blocks when the file system can, and else copy the bytes.
Clone#
CloneShare the data blocks, or fail when the file system cannot.
OPEN_READ_ONLY#
pub const OPEN_READ_ONLY: i32Open for reading only.
OPEN_WRITE_ONLY#
pub const OPEN_WRITE_ONLY: i32Open for writing only.
OPEN_READ_WRITE#
pub const OPEN_READ_WRITE: i32Open for reading and writing.
OPEN_APPEND#
pub const OPEN_APPEND: i32Write each time at the end of the file.
OPEN_CREATE#
pub const OPEN_CREATE: i32Make the file when it does not exist.
OPEN_TRUNCATE#
pub const OPEN_TRUNCATE: i32Make the file length zero.
OPEN_EXCLUSIVE#
pub const OPEN_EXCLUSIVE: i32With OPEN_CREATE, fail when the file exists.
OPEN_NO_FOLLOW#
pub const OPEN_NO_FOLLOW: i32Fail when the last part of the path is a symbolic link.
OPEN_SYNCHRONOUS#
pub const OPEN_SYNCHRONOUS: i32Wait for data and status to reach the device on each write.
OPEN_DATA_SYNCHRONOUS#
pub const OPEN_DATA_SYNCHRONOUS: i32Wait for data to reach the device on each write.
OPEN_DIRECTORY#
pub const OPEN_DIRECTORY: i32Fail when the path is not a directory.
OPEN_NONBLOCK#
pub const OPEN_NONBLOCK: i32Do not block on reads and writes.
OPEN_NO_TERMINAL#
pub const OPEN_NO_TERMINAL: i32Do not make a terminal the controlling terminal.
OPEN_CLOSE_ON_EXEC#
pub const OPEN_CLOSE_ON_EXEC: i32Close the descriptor in a child program.
OPEN_SYMBOLIC_LINK#
pub const OPEN_SYMBOLIC_LINK: i32Open a symbolic link itself, on Darwin.
OPEN_NO_ACCESS_TIME#
pub const OPEN_NO_ACCESS_TIME: i32Do not change the access time, on Linux. Zero on Darwin.
OPEN_DIRECT#
pub const OPEN_DIRECT: i32Bypass the cache, on Linux. Zero on Darwin.
NativeFile#
pub struct NativeFileFile and directory operations on host paths and descriptors.
Details#
A path is bytes. A relative path starts at the working directory. Each path, with its final zero
byte, must fit in PATH_LIMIT bytes. A call that a signal interrupts is made again. The
operations block the calling thread. Each one fails with NativeFileError and the errno
value.
Gotchas#
A descriptor from NativeFile.open belongs to the caller. Nothing closes it on a drop.
Implementation NativeFile#
impl NativeFileAssociated function open#
pub effect fn open(path: &[u8], flags: i32, mode: u32) -> i32 ! NativeFileErrorOpens path with the open flags of this module, such as OPEN_READ_WRITE, and returns the
new descriptor.
Details#
mode gives the permission bits of a new file, filtered by the umask of the process. It is
used only with OPEN_CREATE.
Associated function close#
pub effect fn close(fd: i32) -> () ! NativeFileErrorCloses fd.
Gotchas#
The descriptor is closed also when the close fails. Do not close it again.
Associated function read#
pub effect fn read(fd: i32, buffer: &mut [u8], position: Option<u64>) -> usize ! NativeFileErrorReads at most buffer.length bytes from fd into the start of buffer, and returns their
number. Zero means the end of the file.
Details#
With position set, the read starts at that byte and does not move the file offset. With
none, it starts at the file offset and moves it.
Associated function write#
pub effect fn write(fd: i32, bytes: &[u8], position: Option<u64>) -> usize ! NativeFileErrorWrites at most all of bytes to fd, and returns the number written.
Details#
With position set, the write starts at that byte and does not move the file offset. With
none, it starts at the file offset, or at the end for OPEN_APPEND, and moves it. The
count can be less than bytes.length.
Associated function readScatter#
pub effect fn readScatter(fd: i32, buffers: &mut [&mut [u8]], position: Option<u64>) -> usize ! NativeFileErrorReads from fd into buffers in order, as one read, and returns the number of bytes read.
Details#
At most 1024 buffers are used. position acts as for NativeFile.read.
Associated function writeGather#
pub effect fn writeGather(fd: i32, parts: &[&[u8]], position: Option<u64>) -> usize ! NativeFileErrorWrites parts to fd in order, as one write, and returns the number of bytes written.
Details#
At most 1024 parts are used. position acts as for NativeFile.write. The count can be
less than the sum of the lengths, and can end inside any part.
Associated function status#
pub effect fn status(path: &[u8], followLinks: bool) -> FileStatus ! NativeFileErrorReturns the status of path. With followLinks false, a final symbolic link is inspected
itself.
Associated function statusOf#
pub effect fn statusOf(fd: i32) -> FileStatus ! NativeFileErrorReturns the status of the open descriptor fd.
Associated function truncate#
pub effect fn truncate(path: &[u8], length: u64) -> () ! NativeFileErrorSets the length of the file at path to length bytes. A longer file reads as zeros past
its old end.
Associated function truncateOf#
pub effect fn truncateOf(fd: i32, length: u64) -> () ! NativeFileErrorSets the length of the open file fd to length bytes.
Associated function synchronize#
pub effect fn synchronize(fd: i32, dataOnly: bool) -> () ! NativeFileErrorWaits until the data of fd reaches the device, and its status too unless dataOnly.
Details#
Darwin has no public data-only call, so dataOnly waits for the status there too.
Associated function setTimes#
pub effect fn setTimes(path: &[u8], accessed: Timestamp, modified: Timestamp, followLinks: bool) -> () ! NativeFileErrorSets the access and modification times of path. With followLinks false, a final symbolic
link is changed itself.
Associated function setTimesOf#
pub effect fn setTimesOf(fd: i32, accessed: Timestamp, modified: Timestamp) -> () ! NativeFileErrorSets the access and modification times of the open file fd.
Associated function changeMode#
pub effect fn changeMode(path: &[u8], mode: u32, followLinks: bool) -> () ! NativeFileErrorSets the permission bits of path to mode. With followLinks false, a final symbolic link
is changed itself.
Gotchas#
Linux cannot change the mode of a link: with followLinks false and a final link, the call
fails with code 95 (EOPNOTSUPP).
Associated function changeModeOf#
pub effect fn changeModeOf(fd: i32, mode: u32) -> () ! NativeFileErrorSets the permission bits of the open file fd to mode.
Associated function changeOwner#
pub effect fn changeOwner(path: &[u8], user: u32, group: u32, followLinks: bool) -> () ! NativeFileErrorSets the owner user and group of path. A value of 4294967295 keeps that id. With
followLinks false, a final symbolic link is changed itself.
Associated function changeOwnerOf#
pub effect fn changeOwnerOf(fd: i32, user: u32, group: u32) -> () ! NativeFileErrorSets the owner user and group of the open file fd. A value of 4294967295 keeps that id.
Associated function link#
pub effect fn link(existing: &[u8], created: &[u8]) -> () ! NativeFileErrorMakes created a new hard link to the file existing.
Associated function symbolicLink#
pub effect fn symbolicLink(target: &[u8], path: &[u8]) -> () ! NativeFileErrorMakes path a symbolic link that holds target. The target is stored as it is, and need not
exist.
Associated function readLink#
pub effect fn readLink(path: &[u8], output: &mut [u8]) -> usize ! NativeFileErrorWrites the target of the symbolic link path to the start of output, and returns its
length.
Details#
A target longer than output is cut to output.length bytes; compare the result with
output.length and read again with a larger buffer when they are equal.
Associated function realPath#
pub effect fn realPath(path: &[u8], output: &mut [u8]) -> usize ! NativeFileErrorWrites the absolute path of path with no symbolic links and no . or .. parts to the
start of output, and returns its length.
Details#
A result longer than output fails with code 36 on Linux or 63 on Darwin (ENAMETOOLONG).
Associated function rename#
pub effect fn rename(from: &[u8], to: &[u8]) -> () ! NativeFileErrorMoves from to to, and replaces a file at to.
Associated function remove#
pub effect fn remove(path: &[u8]) -> () ! NativeFileErrorRemoves the file or link path. A final symbolic link is removed itself.
Associated function removeDirectory#
pub effect fn removeDirectory(path: &[u8]) -> () ! NativeFileErrorRemoves the empty directory path.
Associated function makeDirectory#
pub effect fn makeDirectory(path: &[u8], mode: u32) -> () ! NativeFileErrorMakes the directory path with the permission bits mode, filtered by the umask.
Associated function makeTemporaryDirectory#
pub effect fn makeTemporaryDirectory(template: &[u8], output: &mut [u8]) -> usize ! NativeFileErrorMakes a new directory with a unique name, and writes its path to the start of output.
Returns the length of the path.
Details#
template must end with XXXXXX; those six bytes are replaced to make the name unique. The
directory has mode 0700. output must have at least template.length bytes, or the call
fails with code 22 (EINVAL).
Associated function copy#
pub effect fn copy(from: &[u8], to: &[u8], exclusive: bool, method: CopyMethod) -> () ! NativeFileErrorCopies the file from to to with method. The copy gets the permission bits of from.
Details#
With exclusive, the call fails with code 17 (EEXIST) when to exists. Else a file at to
is replaced. A byte copy uses copy_file_range on Linux and fcopyfile on Darwin. A clone
uses FICLONE on Linux and clonefile on Darwin.
Associated function access#
pub effect fn access(path: &[u8], mode: i32) -> () ! NativeFileErrorChecks that the process may use path with mode: 0 for existence, or the sum of 4 for
reading, 2 for writing and 1 for running.
Associated function volumeStatus#
pub effect fn volumeStatus(path: &[u8]) -> VolumeStatus ! NativeFileErrorReturns the status of the file system that holds path.
Associated function openDirectory#
pub effect fn openDirectory(path: &[u8]) -> Directory ! NativeFileErrorOpens the directory path to list its entries with Directory.next.
Directory#
pub struct DirectoryAn open directory listing from NativeFile.openDirectory. Dropping it closes the listing.
Details#
Directory.next returns the entries in the order of the file system, including . and ...
Implementation Directory#
impl DirectoryMethod next#
pub effect fn next(self: &mut Self, output: &mut [u8]) -> Option<DirectoryEntry> ! NativeFileErrorWrites the name of the next entry to the start of output, and returns its length and type,
or none after the last entry.
Details#
A name longer than output fails with code 36 on Linux or 63 on Darwin (ENAMETOOLONG); an
output of 1024 bytes holds every name.
Method close#
pub effect fn close(self: Self) -> () ! NativeFileErrorCloses the listing, and reports a close error.
Implementation Drop for Directory#
impl Drop for DirectoryOperation drop#
fn drop(self: &mut Directory) -> ()TYPE_MASK#
pub const TYPE_MASK: u32The bits of a status mode that give the file type.
TYPE_FILE#
pub const TYPE_FILE: u32The type bits of a regular file.
TYPE_DIRECTORY#
pub const TYPE_DIRECTORY: u32The type bits of a directory.
TYPE_SYMBOLIC_LINK#
pub const TYPE_SYMBOLIC_LINK: u32The type bits of a symbolic link.
TYPE_FIFO#
pub const TYPE_FIFO: u32The type bits of a named pipe.
TYPE_SOCKET#
pub const TYPE_SOCKET: u32The type bits of a socket.
TYPE_CHARACTER_DEVICE#
pub const TYPE_CHARACTER_DEVICE: u32The type bits of a character device.
TYPE_BLOCK_DEVICE#
pub const TYPE_BLOCK_DEVICE: u32The type bits of a block device.
Category: Native platform.
Profiles: aarch64-apple-darwin.