silk.system.filesystem_native.
The native provider of the FileSystem effect, confined to one directory of the host.
When to use#
Provide OsFileSystem for FileSystem in a native program. Code that uses files uses
silk.system.filesystem, so a test can provide a file system in memory.
Details#
OsFileSystem.make takes a root directory of the host. The path / of the provider is that
root, not the root of the host. A path cannot leave the root: .. is not valid in a Path, and
the native provider resolves a symbolic link below the root inside the root. An absolute link
target starts again at the root, and .. in a target never goes above it.
The write operations are different:
writeFilecreates or truncates the file, then writes. If it fails, a partial file can stay.createFilefails withAlreadyExistsif the entry exists. If a later write fails, the new partial file stays.writeFileAtomicwrites a temporary file in the same directory, then renames it to the path (to replace) or links it (to create). A reader sees the old file or the complete new file, never a part. A replace changes a final symbolic link itself, not its target.
New files get mode 0666, filtered by the umask of the process. An atomic replace makes a new
file, so the permissions, owner, extended attributes, and hard links of the old file are not
kept. A synchronized atomic write calls fsync on the file before the rename, and on the
directory after it. syncDirectory also uses fsync. These do not use F_FULLFSYNC, and do
not promise that data survives a power loss.
On WASI, roots name preopened guest directories. The host controls rights, file permissions, and synchronization support.
Directory listings are sorted by the bytes of the paths. A native error becomes a FileError
with a portable reason and the native code.
Errors#
FileErrorfor each failed operation. If a close fails after an earlier error, the earlier error is returned.AtomicWriteErrorfromwriteFileAtomic. It tells if the failure was before or after the new contents became visible, and names a temporary file that cleanup could not remove.OutOfMemoryErrorfrom operations that return owned bytes or paths.
Gotchas#
Trust the root and its parent directories. The confinement does not protect against a process that renames those directories, changes mounts, or changes the temporary files.
After
writeFileAtomicfails with a published error, the new contents are visible. Do not write again without a check.The provider exists on WASI, Darwin on aarch64, and Linux with GNU libc on x86_64 or aarch64.
Examples#
Write and read a file in a temporary directory#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.collections.bytes { Bytes }
import silk.core.effect { Effect }
import silk.system.filesystem { FileError, FileSystem, Path }
import silk.system.filesystem_native { OsFileSystem }
effect fn program() -> i32
! FileError | OutOfMemoryError
? &mut FileSystem | &mut Allocator {
// `/` is the root of the provider: /tmp on the host.
let root = run Path.make("/")
let scratch = run FileSystem.temporaryDirectory(&root, "silk-doc-")
let file = run Path.join(&scratch.path, "note.txt")
run FileSystem.writeFile(&file, b"hello")
let bytes = run FileSystem.readFile(&file)
let read = Bytes.asSlice(&bytes)
let same = read.length == 5 && read[0] == 104
drop read
// Remove the directory and the file in it.
run FileSystem.release(move scratch)
if !same {
return 1
}
return 0
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
effect fn withFiles() -> i32
! FileError | OutOfMemoryError
? &mut Allocator {
let mut files = run OsFileSystem.make("/tmp")
return run program() |> Effect.provideMut<FileSystem>(&mut files)
}
pub fn main() -> i32 {
let mut allocator = Allocator.systemAllocatorProvider()
return run Effect.catchAll(withFiles(), failed) |> Effect.provideMut<Allocator>(&mut allocator)
}Import as OsFileSystem with import silk.system.filesystem_native { OsFileSystem }.
Public declarations: 1.
OsFileSystem#
pub struct OsFileSystemThe native FileSystem provider. It owns the bytes of its root directory.
Details#
Each Path is resolved below the root. The root is never shown as a Path. An operation that
would leave the root fails. The path / of the provider is the root, not the root of the
host. The native provider resolves symbolic links below the root inside the root. New files
get mode 0666, filtered by the umask of the process. Directory listings are sorted by the
bytes of the paths. A native error becomes a FileError with a portable reason and the native code.
On WASI, the root names a preopened guest directory. The host controls rights, permissions, and synchronization support.
Gotchas#
Trust the root and its parent directories. The confinement does not protect against a process that renames those directories, changes mounts, or changes the temporary files of
writeFileAtomic.writeFileandcreateFilecan leave a partial file when a write fails. UsewriteFileAtomicwhen a reader must see the old file or the complete new file.Synchronized writes use
fsync, notF_FULLFSYNC, and do not promise that data survives a power loss.The provider exists on WASI, Darwin on aarch64, and Linux with GNU libc on x86_64 or aarch64.
Implementation OsFileSystem#
impl OsFileSystemImplementation OsFileSystem#
impl OsFileSystemAssociated function make#
pub effect fn make(root: string) -> OsFileSystem ! OutOfMemoryError ? &mut AllocatorReturns a provider with a copy of the text root as its root directory, such as "/" or
"/tmp". It does not open the directory.
Errors#
OutOfMemoryError if the copy cannot be allocated.
Gotchas#
root must be an absolute host path, not empty, with no NUL. Other values trap.
Associated function makeBytes#
pub effect fn makeBytes(root: &[u8]) -> OsFileSystem ! OutOfMemoryError ? &mut AllocatorReturns a provider with a copy of root as its root directory. It does not open the
directory. The bytes do not have to be valid UTF-8.
When to use#
Use it for a root that you got from the host as bytes, such as the working directory from
HostInput.workingDirectory.
Errors#
OutOfMemoryError if the copy cannot be allocated.
Gotchas#
root must be an absolute host path, not empty, with no NUL. Other values trap.
Implementation FileSystem for OsFileSystem#
impl FileSystem for OsFileSystemOperation readFile#
readFile: OsFileSystem.readFileOperation writeFile#
writeFile: OsFileSystem.writeFileOperation createFile#
createFile: OsFileSystem.createFileOperation writeFileAtomic#
writeFileAtomic: OsFileSystem.writeFileAtomicOperation syncDirectory#
syncDirectory: OsFileSystem.syncDirectoryOperation stat#
stat: OsFileSystem.statOperation listDirectory#
listDirectory: OsFileSystem.listDirectoryOperation createDirectory#
createDirectory: OsFileSystem.createDirectoryOperation removeFile#
removeFile: OsFileSystem.removeFileOperation removeDirectory#
removeDirectory: OsFileSystem.removeDirectoryOperation createTemporaryDirectory#
createTemporaryDirectory: OsFileSystem.createTemporaryDirectoryCategory: System.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, x86_64-unknown-linux-gnu, wasm32-wasip1, wasm32-wasip2.