Compare commits
1 Commits
git-panel-
...
wasi-fs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b1a4a0419 |
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -4066,6 +4066,7 @@ dependencies = [
|
|||||||
"ui",
|
"ui",
|
||||||
"url",
|
"url",
|
||||||
"util",
|
"util",
|
||||||
|
"wasi_fs",
|
||||||
"wasm-encoder 0.201.0",
|
"wasm-encoder 0.201.0",
|
||||||
"wasmparser 0.201.0",
|
"wasmparser 0.201.0",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
@@ -12702,6 +12703,27 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi_fs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"collections",
|
||||||
|
"fs",
|
||||||
|
"futures 0.3.30",
|
||||||
|
"gpui",
|
||||||
|
"log",
|
||||||
|
"parking_lot",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"util",
|
||||||
|
"wasmparser 0.201.0",
|
||||||
|
"wasmtime",
|
||||||
|
"wasmtime-wasi",
|
||||||
|
"wit-component",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasite"
|
name = "wasite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ members = [
|
|||||||
"crates/util",
|
"crates/util",
|
||||||
"crates/vcs_menu",
|
"crates/vcs_menu",
|
||||||
"crates/vim",
|
"crates/vim",
|
||||||
|
"crates/wasi_fs",
|
||||||
"crates/welcome",
|
"crates/welcome",
|
||||||
"crates/workspace",
|
"crates/workspace",
|
||||||
"crates/worktree",
|
"crates/worktree",
|
||||||
@@ -297,6 +298,7 @@ ui_input = { path = "crates/ui_input" }
|
|||||||
util = { path = "crates/util" }
|
util = { path = "crates/util" }
|
||||||
vcs_menu = { path = "crates/vcs_menu" }
|
vcs_menu = { path = "crates/vcs_menu" }
|
||||||
vim = { path = "crates/vim" }
|
vim = { path = "crates/vim" }
|
||||||
|
wasi_fs = { path = "crates/wasi_fs" }
|
||||||
welcome = { path = "crates/welcome" }
|
welcome = { path = "crates/welcome" }
|
||||||
workspace = { path = "crates/workspace" }
|
workspace = { path = "crates/workspace" }
|
||||||
worktree = { path = "crates/worktree" }
|
worktree = { path = "crates/worktree" }
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ util.workspace = true
|
|||||||
wasm-encoder.workspace = true
|
wasm-encoder.workspace = true
|
||||||
wasmtime.workspace = true
|
wasmtime.workspace = true
|
||||||
wasmtime-wasi.workspace = true
|
wasmtime-wasi.workspace = true
|
||||||
|
wasi_fs.workspace = true
|
||||||
wasmparser.workspace = true
|
wasmparser.workspace = true
|
||||||
wit-component.workspace = true
|
wit-component.workspace = true
|
||||||
workspace.workspace = true
|
workspace.workspace = true
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use anyhow::{anyhow, Result};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use indexed_docs::{IndexedDocsDatabase, IndexedDocsProvider, PackageName, ProviderId};
|
use indexed_docs::{IndexedDocsDatabase, IndexedDocsProvider, PackageName, ProviderId};
|
||||||
use wasmtime_wasi::WasiView;
|
|
||||||
|
|
||||||
use crate::wasm_host::{WasmExtension, WasmHost};
|
use crate::wasm_host::{WasmExtension, WasmHost};
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::{maybe, ResultExt};
|
use util::{maybe, ResultExt};
|
||||||
use wasmtime_wasi::WasiView as _;
|
|
||||||
|
|
||||||
pub struct ExtensionLspAdapter {
|
pub struct ExtensionLspAdapter {
|
||||||
pub(crate) extension: WasmExtension,
|
pub(crate) extension: WasmExtension,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use futures::FutureExt;
|
|||||||
use gpui::{Task, WeakView, WindowContext};
|
use gpui::{Task, WeakView, WindowContext};
|
||||||
use language::LspAdapterDelegate;
|
use language::LspAdapterDelegate;
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
use wasmtime_wasi::WasiView;
|
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
||||||
use crate::wasm_host::{WasmExtension, WasmHost};
|
use crate::wasm_host::{WasmExtension, WasmHost};
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ use wasmtime::{
|
|||||||
component::{Component, ResourceTable},
|
component::{Component, ResourceTable},
|
||||||
Engine, Store,
|
Engine, Store,
|
||||||
};
|
};
|
||||||
use wasmtime_wasi as wasi;
|
|
||||||
use wit::Extension;
|
use wit::Extension;
|
||||||
|
|
||||||
pub(crate) struct WasmHost {
|
pub(crate) struct WasmHost {
|
||||||
@@ -52,7 +51,7 @@ pub struct WasmExtension {
|
|||||||
pub(crate) struct WasmState {
|
pub(crate) struct WasmState {
|
||||||
manifest: Arc<ExtensionManifest>,
|
manifest: Arc<ExtensionManifest>,
|
||||||
pub(crate) table: ResourceTable,
|
pub(crate) table: ResourceTable,
|
||||||
ctx: wasi::WasiCtx,
|
fs: Arc<dyn Fs>,
|
||||||
pub(crate) host: Arc<WasmHost>,
|
pub(crate) host: Arc<WasmHost>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +119,7 @@ impl WasmHost {
|
|||||||
let mut store = wasmtime::Store::new(
|
let mut store = wasmtime::Store::new(
|
||||||
&this.engine,
|
&this.engine,
|
||||||
WasmState {
|
WasmState {
|
||||||
ctx: this.build_wasi_ctx(&manifest).await?,
|
fs: this.fs.clone(),
|
||||||
manifest: manifest.clone(),
|
manifest: manifest.clone(),
|
||||||
table: ResourceTable::new(),
|
table: ResourceTable::new(),
|
||||||
host: this.clone(),
|
host: this.clone(),
|
||||||
@@ -158,30 +157,6 @@ impl WasmHost {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn build_wasi_ctx(&self, manifest: &Arc<ExtensionManifest>) -> Result<wasi::WasiCtx> {
|
|
||||||
let extension_work_dir = self.work_dir.join(manifest.id.as_ref());
|
|
||||||
self.fs
|
|
||||||
.create_dir(&extension_work_dir)
|
|
||||||
.await
|
|
||||||
.context("failed to create extension work dir")?;
|
|
||||||
|
|
||||||
let file_perms = wasi::FilePerms::all();
|
|
||||||
let dir_perms = wasi::DirPerms::all();
|
|
||||||
|
|
||||||
Ok(wasi::WasiCtxBuilder::new()
|
|
||||||
.inherit_stdio()
|
|
||||||
.preopened_dir(&extension_work_dir, ".", dir_perms, file_perms)?
|
|
||||||
.preopened_dir(
|
|
||||||
&extension_work_dir,
|
|
||||||
&extension_work_dir.to_string_lossy(),
|
|
||||||
dir_perms,
|
|
||||||
file_perms,
|
|
||||||
)?
|
|
||||||
.env("PWD", &extension_work_dir.to_string_lossy())
|
|
||||||
.env("RUST_BACKTRACE", "full")
|
|
||||||
.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path_from_extension(&self, id: &Arc<str>, path: &Path) -> PathBuf {
|
pub fn path_from_extension(&self, id: &Arc<str>, path: &Path) -> PathBuf {
|
||||||
let extension_work_dir = self.work_dir.join(id.as_ref());
|
let extension_work_dir = self.work_dir.join(id.as_ref());
|
||||||
normalize_path(&extension_work_dir.join(path))
|
normalize_path(&extension_work_dir.join(path))
|
||||||
@@ -288,14 +263,18 @@ impl WasmState {
|
|||||||
fn work_dir(&self) -> PathBuf {
|
fn work_dir(&self) -> PathBuf {
|
||||||
self.host.work_dir.join(self.manifest.id.as_ref())
|
self.host.work_dir.join(self.manifest.id.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn table(&mut self) -> &mut ResourceTable {
|
||||||
|
&mut self.table
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wasi::WasiView for WasmState {
|
impl wasi_fs::WasiFsView for WasmState {
|
||||||
fn table(&mut self) -> &mut ResourceTable {
|
fn table(&mut self) -> &mut ResourceTable {
|
||||||
&mut self.table
|
&mut self.table
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ctx(&mut self) -> &mut wasi::WasiCtx {
|
fn fs(&self) -> &Arc<dyn Fs> {
|
||||||
&mut self.ctx
|
&self.fs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub fn new_linker(
|
|||||||
f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
|
f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
|
||||||
) -> Linker<WasmState> {
|
) -> Linker<WasmState> {
|
||||||
let mut linker = Linker::new(&wasm_engine());
|
let mut linker = Linker::new(&wasm_engine());
|
||||||
wasmtime_wasi::add_to_linker_async(&mut linker).unwrap();
|
wasi_fs::add_to_linker(&mut linker).unwrap();
|
||||||
f(&mut linker, wasi_view).unwrap();
|
f(&mut linker, wasi_view).unwrap();
|
||||||
linker
|
linker
|
||||||
}
|
}
|
||||||
|
|||||||
34
crates/wasi_fs/Cargo.toml
Normal file
34
crates/wasi_fs/Cargo.toml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasi_fs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/wasi_fs.rs"
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-trait.workspace = true
|
||||||
|
anyhow.workspace = true
|
||||||
|
collections.workspace = true
|
||||||
|
fs.workspace = true
|
||||||
|
futures.workspace = true
|
||||||
|
gpui.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
parking_lot.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
util.workspace = true
|
||||||
|
wasmtime.workspace = true
|
||||||
|
wasmtime-wasi.workspace = true
|
||||||
|
wasmparser.workspace = true
|
||||||
|
wit-component.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
fs = { workspace = true, features = ["test-support"] }
|
||||||
|
gpui = { workspace = true, features = ["test-support"] }
|
||||||
395
crates/wasi_fs/src/wasi_fs.rs
Normal file
395
crates/wasi_fs/src/wasi_fs.rs
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use fs::Fs;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wasi::{
|
||||||
|
filesystem::{
|
||||||
|
preopens,
|
||||||
|
types::{self, ErrorCode, HostDescriptor, HostDirectoryEntryStream},
|
||||||
|
},
|
||||||
|
io::streams,
|
||||||
|
};
|
||||||
|
use wasmtime::component::{Linker, Resource, ResourceTable};
|
||||||
|
|
||||||
|
pub trait WasiFsView: Send {
|
||||||
|
fn table(&mut self) -> &mut ResourceTable;
|
||||||
|
fn fs(&self) -> &Arc<dyn Fs>;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
path: "wit",
|
||||||
|
world: "wasi:filesystem/imports",
|
||||||
|
trappable_imports: true,
|
||||||
|
async: {
|
||||||
|
only_imports: [
|
||||||
|
"[method]descriptor.access-at",
|
||||||
|
"[method]descriptor.advise",
|
||||||
|
"[method]descriptor.change-directory-permissions-at",
|
||||||
|
"[method]descriptor.change-file-permissions-at",
|
||||||
|
"[method]descriptor.create-directory-at",
|
||||||
|
"[method]descriptor.get-flags",
|
||||||
|
"[method]descriptor.get-type",
|
||||||
|
"[method]descriptor.is-same-object",
|
||||||
|
"[method]descriptor.link-at",
|
||||||
|
"[method]descriptor.lock-exclusive",
|
||||||
|
"[method]descriptor.lock-shared",
|
||||||
|
"[method]descriptor.metadata-hash",
|
||||||
|
"[method]descriptor.metadata-hash-at",
|
||||||
|
"[method]descriptor.open-at",
|
||||||
|
"[method]descriptor.read",
|
||||||
|
"[method]descriptor.read-directory",
|
||||||
|
"[method]descriptor.readlink-at",
|
||||||
|
"[method]descriptor.remove-directory-at",
|
||||||
|
"[method]descriptor.rename-at",
|
||||||
|
"[method]descriptor.set-size",
|
||||||
|
"[method]descriptor.set-times",
|
||||||
|
"[method]descriptor.set-times-at",
|
||||||
|
"[method]descriptor.stat",
|
||||||
|
"[method]descriptor.stat-at",
|
||||||
|
"[method]descriptor.symlink-at",
|
||||||
|
"[method]descriptor.sync",
|
||||||
|
"[method]descriptor.sync-data",
|
||||||
|
"[method]descriptor.try-lock-exclusive",
|
||||||
|
"[method]descriptor.try-lock-shared",
|
||||||
|
"[method]descriptor.unlink-file-at",
|
||||||
|
"[method]descriptor.unlock",
|
||||||
|
"[method]descriptor.write",
|
||||||
|
"[method]input-stream.read",
|
||||||
|
"[method]input-stream.blocking-read",
|
||||||
|
"[method]input-stream.blocking-skip",
|
||||||
|
"[method]input-stream.skip",
|
||||||
|
"[method]output-stream.forward",
|
||||||
|
"[method]output-stream.splice",
|
||||||
|
"[method]output-stream.blocking-splice",
|
||||||
|
"[method]output-stream.blocking-flush",
|
||||||
|
"[method]output-stream.blocking-write",
|
||||||
|
"[method]output-stream.blocking-write-and-flush",
|
||||||
|
"[method]output-stream.blocking-write-zeroes-and-flush",
|
||||||
|
"[method]directory-entry-stream.read-directory-entry",
|
||||||
|
"poll",
|
||||||
|
"[method]pollable.block",
|
||||||
|
"[method]pollable.ready",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
trappable_error_type: {
|
||||||
|
"wasi:io/streams/stream-error" => StreamError,
|
||||||
|
"wasi:filesystem/types/error-code" => FsError,
|
||||||
|
},
|
||||||
|
with: {
|
||||||
|
"wasi:filesystem/types/directory-entry-stream": ReaddirIterator,
|
||||||
|
"wasi:filesystem/types/descriptor": Descriptor,
|
||||||
|
"wasi:io/streams/input-stream": InputStream,
|
||||||
|
"wasi:io/streams/output-stream": OutputStream,
|
||||||
|
"wasi:io/error/error": StreamError,
|
||||||
|
"wasi:io/poll/pollable": Pollable,
|
||||||
|
},
|
||||||
|
skip_mut_forwarding_impls: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn add_to_linker<T: WasiFsView + 'static>(linker: &mut Linker<T>) -> Result<()> {
|
||||||
|
fn id<'a, T>(state: &'a mut T) -> &'a mut T {
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
wasi::filesystem::types::add_to_linker_get_host(linker, id)?;
|
||||||
|
wasi::filesystem::preopens::add_to_linker_get_host(linker, id)?;
|
||||||
|
wasi::io::streams::add_to_linker_get_host(linker, id)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: WasiFsView> WasiFsView for &mut T {
|
||||||
|
fn table(&mut self) -> &mut ResourceTable {
|
||||||
|
T::table(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fs(&self) -> &Arc<dyn Fs> {
|
||||||
|
T::fs(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> HostDescriptor for T {
|
||||||
|
async fn advise(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_offset: types::Filesize,
|
||||||
|
_len: types::Filesize,
|
||||||
|
_advice: types::Advice,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn sync_data(&mut self, _fd: Resource<types::Descriptor>) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_flags(&mut self, _fd: Resource<Descriptor>) -> FsResult<types::DescriptorFlags> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_type(&mut self, _fd: Resource<Descriptor>) -> FsResult<types::DescriptorType> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_size(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_size: types::Filesize,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_times(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_atim: types::NewTimestamp,
|
||||||
|
_mtim: types::NewTimestamp,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_len: types::Filesize,
|
||||||
|
_offset: types::Filesize,
|
||||||
|
) -> FsResult<(Vec<u8>, bool)> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_buf: Vec<u8>,
|
||||||
|
_offset: types::Filesize,
|
||||||
|
) -> FsResult<types::Filesize> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_directory(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
) -> FsResult<Resource<types::DirectoryEntryStream>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn sync(&mut self, _fd: Resource<Descriptor>) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_directory_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_path: String,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stat(&mut self, _fd: Resource<Descriptor>) -> FsResult<types::DescriptorStat> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stat_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_path_flags: types::PathFlags,
|
||||||
|
_path: String,
|
||||||
|
) -> FsResult<types::DescriptorStat> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_times_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_path_flags: types::PathFlags,
|
||||||
|
_path: String,
|
||||||
|
_atim: types::NewTimestamp,
|
||||||
|
_mtim: types::NewTimestamp,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn link_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_old_path_flags: types::PathFlags,
|
||||||
|
_old_path: String,
|
||||||
|
_new_descriptor: Resource<Descriptor>,
|
||||||
|
_new_path: String,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn open_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<Descriptor>,
|
||||||
|
_path_flags: types::PathFlags,
|
||||||
|
_path: String,
|
||||||
|
_oflags: types::OpenFlags,
|
||||||
|
_flags: types::DescriptorFlags,
|
||||||
|
) -> FsResult<Resource<types::Descriptor>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop(&mut self, _fd: Resource<types::Descriptor>) -> anyhow::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn readlink_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_path: String,
|
||||||
|
) -> FsResult<String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_directory_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_path: String,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn rename_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_old_path: String,
|
||||||
|
_new_fd: Resource<types::Descriptor>,
|
||||||
|
_new_path: String,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn symlink_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_src_path: String,
|
||||||
|
_dest_path: String,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unlink_file_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_path: String,
|
||||||
|
) -> FsResult<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_via_stream(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_offset: types::Filesize,
|
||||||
|
) -> FsResult<Resource<InputStream>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_via_stream(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_offset: types::Filesize,
|
||||||
|
) -> FsResult<Resource<OutputStream>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_via_stream(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
) -> FsResult<Resource<OutputStream>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_same_object(
|
||||||
|
&mut self,
|
||||||
|
_a: Resource<types::Descriptor>,
|
||||||
|
_b: Resource<types::Descriptor>,
|
||||||
|
) -> anyhow::Result<bool> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn metadata_hash(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
) -> FsResult<types::MetadataHashValue> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn metadata_hash_at(
|
||||||
|
&mut self,
|
||||||
|
_fd: Resource<types::Descriptor>,
|
||||||
|
_path_flags: types::PathFlags,
|
||||||
|
_path: String,
|
||||||
|
) -> FsResult<types::MetadataHashValue> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> HostDirectoryEntryStream for T {
|
||||||
|
async fn read_directory_entry(
|
||||||
|
&mut self,
|
||||||
|
_stream: Resource<types::DirectoryEntryStream>,
|
||||||
|
) -> FsResult<Option<types::DirectoryEntry>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop(&mut self, _stream: Resource<types::DirectoryEntryStream>) -> anyhow::Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> types::Host for T {
|
||||||
|
fn convert_error_code(&mut self, _err: FsError) -> anyhow::Result<ErrorCode> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filesystem_error_code(
|
||||||
|
&mut self,
|
||||||
|
_err: Resource<StreamError>,
|
||||||
|
) -> anyhow::Result<Option<ErrorCode>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> streams::Host for T {
|
||||||
|
fn convert_stream_error(&mut self, err: StreamError) -> anyhow::Result<streams::StreamError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> streams::HostOutputStream for T {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> streams::HostInputStream for T {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<T: WasiFsView> preopens::Host for T {
|
||||||
|
fn get_directories(
|
||||||
|
&mut self,
|
||||||
|
) -> Result<Vec<(Resource<types::Descriptor>, String)>, anyhow::Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InputStream {}
|
||||||
|
|
||||||
|
pub struct OutputStream {}
|
||||||
|
|
||||||
|
pub struct Descriptor {}
|
||||||
|
|
||||||
|
pub struct ReaddirIterator {}
|
||||||
|
|
||||||
|
pub struct StreamError {}
|
||||||
|
|
||||||
|
pub struct IoError {}
|
||||||
|
|
||||||
|
pub struct Pollable {}
|
||||||
|
|
||||||
|
pub type FsResult<T> = Result<T, FsError>;
|
||||||
|
|
||||||
|
pub struct FsError {}
|
||||||
45
crates/wasi_fs/wit/deps/clocks/monotonic-clock.wit
Normal file
45
crates/wasi_fs/wit/deps/clocks/monotonic-clock.wit
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package wasi:clocks@0.2.0;
|
||||||
|
/// WASI Monotonic Clock is a clock API intended to let users measure elapsed
|
||||||
|
/// time.
|
||||||
|
///
|
||||||
|
/// It is intended to be portable at least between Unix-family platforms and
|
||||||
|
/// Windows.
|
||||||
|
///
|
||||||
|
/// A monotonic clock is a clock which has an unspecified initial value, and
|
||||||
|
/// successive reads of the clock will produce non-decreasing values.
|
||||||
|
///
|
||||||
|
/// It is intended for measuring elapsed time.
|
||||||
|
interface monotonic-clock {
|
||||||
|
use wasi:io/poll@0.2.0.{pollable};
|
||||||
|
|
||||||
|
/// An instant in time, in nanoseconds. An instant is relative to an
|
||||||
|
/// unspecified initial value, and can only be compared to instances from
|
||||||
|
/// the same monotonic-clock.
|
||||||
|
type instant = u64;
|
||||||
|
|
||||||
|
/// A duration of time, in nanoseconds.
|
||||||
|
type duration = u64;
|
||||||
|
|
||||||
|
/// Read the current value of the clock.
|
||||||
|
///
|
||||||
|
/// The clock is monotonic, therefore calling this function repeatedly will
|
||||||
|
/// produce a sequence of non-decreasing values.
|
||||||
|
now: func() -> instant;
|
||||||
|
|
||||||
|
/// Query the resolution of the clock. Returns the duration of time
|
||||||
|
/// corresponding to a clock tick.
|
||||||
|
resolution: func() -> duration;
|
||||||
|
|
||||||
|
/// Create a `pollable` which will resolve once the specified instant
|
||||||
|
/// occured.
|
||||||
|
subscribe-instant: func(
|
||||||
|
when: instant,
|
||||||
|
) -> pollable;
|
||||||
|
|
||||||
|
/// Create a `pollable` which will resolve once the given duration has
|
||||||
|
/// elapsed, starting at the time at which this function was called.
|
||||||
|
/// occured.
|
||||||
|
subscribe-duration: func(
|
||||||
|
when: duration,
|
||||||
|
) -> pollable;
|
||||||
|
}
|
||||||
42
crates/wasi_fs/wit/deps/clocks/wall-clock.wit
Normal file
42
crates/wasi_fs/wit/deps/clocks/wall-clock.wit
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package wasi:clocks@0.2.0;
|
||||||
|
/// WASI Wall Clock is a clock API intended to let users query the current
|
||||||
|
/// time. The name "wall" makes an analogy to a "clock on the wall", which
|
||||||
|
/// is not necessarily monotonic as it may be reset.
|
||||||
|
///
|
||||||
|
/// It is intended to be portable at least between Unix-family platforms and
|
||||||
|
/// Windows.
|
||||||
|
///
|
||||||
|
/// A wall clock is a clock which measures the date and time according to
|
||||||
|
/// some external reference.
|
||||||
|
///
|
||||||
|
/// External references may be reset, so this clock is not necessarily
|
||||||
|
/// monotonic, making it unsuitable for measuring elapsed time.
|
||||||
|
///
|
||||||
|
/// It is intended for reporting the current date and time for humans.
|
||||||
|
interface wall-clock {
|
||||||
|
/// A time and date in seconds plus nanoseconds.
|
||||||
|
record datetime {
|
||||||
|
seconds: u64,
|
||||||
|
nanoseconds: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the current value of the clock.
|
||||||
|
///
|
||||||
|
/// This clock is not monotonic, therefore calling this function repeatedly
|
||||||
|
/// will not necessarily produce a sequence of non-decreasing values.
|
||||||
|
///
|
||||||
|
/// The returned timestamps represent the number of seconds since
|
||||||
|
/// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch],
|
||||||
|
/// also known as [Unix Time].
|
||||||
|
///
|
||||||
|
/// The nanoseconds field of the output is always less than 1000000000.
|
||||||
|
///
|
||||||
|
/// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
|
||||||
|
/// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time
|
||||||
|
now: func() -> datetime;
|
||||||
|
|
||||||
|
/// Query the resolution of the clock.
|
||||||
|
///
|
||||||
|
/// The nanoseconds field of the output is always less than 1000000000.
|
||||||
|
resolution: func() -> datetime;
|
||||||
|
}
|
||||||
6
crates/wasi_fs/wit/deps/clocks/world.wit
Normal file
6
crates/wasi_fs/wit/deps/clocks/world.wit
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package wasi:clocks@0.2.0;
|
||||||
|
|
||||||
|
world imports {
|
||||||
|
import monotonic-clock;
|
||||||
|
import wall-clock;
|
||||||
|
}
|
||||||
8
crates/wasi_fs/wit/deps/filesystem/preopens.wit
Normal file
8
crates/wasi_fs/wit/deps/filesystem/preopens.wit
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package wasi:filesystem@0.2.0;
|
||||||
|
|
||||||
|
interface preopens {
|
||||||
|
use types.{descriptor};
|
||||||
|
|
||||||
|
/// Return the set of preopened directories, and their path.
|
||||||
|
get-directories: func() -> list<tuple<descriptor, string>>;
|
||||||
|
}
|
||||||
634
crates/wasi_fs/wit/deps/filesystem/types.wit
Normal file
634
crates/wasi_fs/wit/deps/filesystem/types.wit
Normal file
@@ -0,0 +1,634 @@
|
|||||||
|
package wasi:filesystem@0.2.0;
|
||||||
|
/// WASI filesystem is a filesystem API primarily intended to let users run WASI
|
||||||
|
/// programs that access their files on their existing filesystems, without
|
||||||
|
/// significant overhead.
|
||||||
|
///
|
||||||
|
/// It is intended to be roughly portable between Unix-family platforms and
|
||||||
|
/// Windows, though it does not hide many of the major differences.
|
||||||
|
///
|
||||||
|
/// Paths are passed as interface-type `string`s, meaning they must consist of
|
||||||
|
/// a sequence of Unicode Scalar Values (USVs). Some filesystems may contain
|
||||||
|
/// paths which are not accessible by this API.
|
||||||
|
///
|
||||||
|
/// The directory separator in WASI is always the forward-slash (`/`).
|
||||||
|
///
|
||||||
|
/// All paths in WASI are relative paths, and are interpreted relative to a
|
||||||
|
/// `descriptor` referring to a base directory. If a `path` argument to any WASI
|
||||||
|
/// function starts with `/`, or if any step of resolving a `path`, including
|
||||||
|
/// `..` and symbolic link steps, reaches a directory outside of the base
|
||||||
|
/// directory, or reaches a symlink to an absolute or rooted path in the
|
||||||
|
/// underlying filesystem, the function fails with `error-code::not-permitted`.
|
||||||
|
///
|
||||||
|
/// For more information about WASI path resolution and sandboxing, see
|
||||||
|
/// [WASI filesystem path resolution].
|
||||||
|
///
|
||||||
|
/// [WASI filesystem path resolution]: https://github.com/WebAssembly/wasi-filesystem/blob/main/path-resolution.md
|
||||||
|
interface types {
|
||||||
|
use wasi:io/streams@0.2.0.{input-stream, output-stream, error};
|
||||||
|
use wasi:clocks/wall-clock@0.2.0.{datetime};
|
||||||
|
|
||||||
|
/// File size or length of a region within a file.
|
||||||
|
type filesize = u64;
|
||||||
|
|
||||||
|
/// The type of a filesystem object referenced by a descriptor.
|
||||||
|
///
|
||||||
|
/// Note: This was called `filetype` in earlier versions of WASI.
|
||||||
|
enum descriptor-type {
|
||||||
|
/// The type of the descriptor or file is unknown or is different from
|
||||||
|
/// any of the other types specified.
|
||||||
|
unknown,
|
||||||
|
/// The descriptor refers to a block device inode.
|
||||||
|
block-device,
|
||||||
|
/// The descriptor refers to a character device inode.
|
||||||
|
character-device,
|
||||||
|
/// The descriptor refers to a directory inode.
|
||||||
|
directory,
|
||||||
|
/// The descriptor refers to a named pipe.
|
||||||
|
fifo,
|
||||||
|
/// The file refers to a symbolic link inode.
|
||||||
|
symbolic-link,
|
||||||
|
/// The descriptor refers to a regular file inode.
|
||||||
|
regular-file,
|
||||||
|
/// The descriptor refers to a socket.
|
||||||
|
socket,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Descriptor flags.
|
||||||
|
///
|
||||||
|
/// Note: This was called `fdflags` in earlier versions of WASI.
|
||||||
|
flags descriptor-flags {
|
||||||
|
/// Read mode: Data can be read.
|
||||||
|
read,
|
||||||
|
/// Write mode: Data can be written to.
|
||||||
|
write,
|
||||||
|
/// Request that writes be performed according to synchronized I/O file
|
||||||
|
/// integrity completion. The data stored in the file and the file's
|
||||||
|
/// metadata are synchronized. This is similar to `O_SYNC` in POSIX.
|
||||||
|
///
|
||||||
|
/// The precise semantics of this operation have not yet been defined for
|
||||||
|
/// WASI. At this time, it should be interpreted as a request, and not a
|
||||||
|
/// requirement.
|
||||||
|
file-integrity-sync,
|
||||||
|
/// Request that writes be performed according to synchronized I/O data
|
||||||
|
/// integrity completion. Only the data stored in the file is
|
||||||
|
/// synchronized. This is similar to `O_DSYNC` in POSIX.
|
||||||
|
///
|
||||||
|
/// The precise semantics of this operation have not yet been defined for
|
||||||
|
/// WASI. At this time, it should be interpreted as a request, and not a
|
||||||
|
/// requirement.
|
||||||
|
data-integrity-sync,
|
||||||
|
/// Requests that reads be performed at the same level of integrety
|
||||||
|
/// requested for writes. This is similar to `O_RSYNC` in POSIX.
|
||||||
|
///
|
||||||
|
/// The precise semantics of this operation have not yet been defined for
|
||||||
|
/// WASI. At this time, it should be interpreted as a request, and not a
|
||||||
|
/// requirement.
|
||||||
|
requested-write-sync,
|
||||||
|
/// Mutating directories mode: Directory contents may be mutated.
|
||||||
|
///
|
||||||
|
/// When this flag is unset on a descriptor, operations using the
|
||||||
|
/// descriptor which would create, rename, delete, modify the data or
|
||||||
|
/// metadata of filesystem objects, or obtain another handle which
|
||||||
|
/// would permit any of those, shall fail with `error-code::read-only` if
|
||||||
|
/// they would otherwise succeed.
|
||||||
|
///
|
||||||
|
/// This may only be set on directories.
|
||||||
|
mutate-directory,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// File attributes.
|
||||||
|
///
|
||||||
|
/// Note: This was called `filestat` in earlier versions of WASI.
|
||||||
|
record descriptor-stat {
|
||||||
|
/// File type.
|
||||||
|
%type: descriptor-type,
|
||||||
|
/// Number of hard links to the file.
|
||||||
|
link-count: link-count,
|
||||||
|
/// For regular files, the file size in bytes. For symbolic links, the
|
||||||
|
/// length in bytes of the pathname contained in the symbolic link.
|
||||||
|
size: filesize,
|
||||||
|
/// Last data access timestamp.
|
||||||
|
///
|
||||||
|
/// If the `option` is none, the platform doesn't maintain an access
|
||||||
|
/// timestamp for this file.
|
||||||
|
data-access-timestamp: option<datetime>,
|
||||||
|
/// Last data modification timestamp.
|
||||||
|
///
|
||||||
|
/// If the `option` is none, the platform doesn't maintain a
|
||||||
|
/// modification timestamp for this file.
|
||||||
|
data-modification-timestamp: option<datetime>,
|
||||||
|
/// Last file status-change timestamp.
|
||||||
|
///
|
||||||
|
/// If the `option` is none, the platform doesn't maintain a
|
||||||
|
/// status-change timestamp for this file.
|
||||||
|
status-change-timestamp: option<datetime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flags determining the method of how paths are resolved.
|
||||||
|
flags path-flags {
|
||||||
|
/// As long as the resolved path corresponds to a symbolic link, it is
|
||||||
|
/// expanded.
|
||||||
|
symlink-follow,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open flags used by `open-at`.
|
||||||
|
flags open-flags {
|
||||||
|
/// Create file if it does not exist, similar to `O_CREAT` in POSIX.
|
||||||
|
create,
|
||||||
|
/// Fail if not a directory, similar to `O_DIRECTORY` in POSIX.
|
||||||
|
directory,
|
||||||
|
/// Fail if file already exists, similar to `O_EXCL` in POSIX.
|
||||||
|
exclusive,
|
||||||
|
/// Truncate file to size 0, similar to `O_TRUNC` in POSIX.
|
||||||
|
truncate,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of hard links to an inode.
|
||||||
|
type link-count = u64;
|
||||||
|
|
||||||
|
/// When setting a timestamp, this gives the value to set it to.
|
||||||
|
variant new-timestamp {
|
||||||
|
/// Leave the timestamp set to its previous value.
|
||||||
|
no-change,
|
||||||
|
/// Set the timestamp to the current time of the system clock associated
|
||||||
|
/// with the filesystem.
|
||||||
|
now,
|
||||||
|
/// Set the timestamp to the given value.
|
||||||
|
timestamp(datetime),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A directory entry.
|
||||||
|
record directory-entry {
|
||||||
|
/// The type of the file referred to by this directory entry.
|
||||||
|
%type: descriptor-type,
|
||||||
|
|
||||||
|
/// The name of the object.
|
||||||
|
name: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error codes returned by functions, similar to `errno` in POSIX.
|
||||||
|
/// Not all of these error codes are returned by the functions provided by this
|
||||||
|
/// API; some are used in higher-level library layers, and others are provided
|
||||||
|
/// merely for alignment with POSIX.
|
||||||
|
enum error-code {
|
||||||
|
/// Permission denied, similar to `EACCES` in POSIX.
|
||||||
|
access,
|
||||||
|
/// Resource unavailable, or operation would block, similar to `EAGAIN` and `EWOULDBLOCK` in POSIX.
|
||||||
|
would-block,
|
||||||
|
/// Connection already in progress, similar to `EALREADY` in POSIX.
|
||||||
|
already,
|
||||||
|
/// Bad descriptor, similar to `EBADF` in POSIX.
|
||||||
|
bad-descriptor,
|
||||||
|
/// Device or resource busy, similar to `EBUSY` in POSIX.
|
||||||
|
busy,
|
||||||
|
/// Resource deadlock would occur, similar to `EDEADLK` in POSIX.
|
||||||
|
deadlock,
|
||||||
|
/// Storage quota exceeded, similar to `EDQUOT` in POSIX.
|
||||||
|
quota,
|
||||||
|
/// File exists, similar to `EEXIST` in POSIX.
|
||||||
|
exist,
|
||||||
|
/// File too large, similar to `EFBIG` in POSIX.
|
||||||
|
file-too-large,
|
||||||
|
/// Illegal byte sequence, similar to `EILSEQ` in POSIX.
|
||||||
|
illegal-byte-sequence,
|
||||||
|
/// Operation in progress, similar to `EINPROGRESS` in POSIX.
|
||||||
|
in-progress,
|
||||||
|
/// Interrupted function, similar to `EINTR` in POSIX.
|
||||||
|
interrupted,
|
||||||
|
/// Invalid argument, similar to `EINVAL` in POSIX.
|
||||||
|
invalid,
|
||||||
|
/// I/O error, similar to `EIO` in POSIX.
|
||||||
|
io,
|
||||||
|
/// Is a directory, similar to `EISDIR` in POSIX.
|
||||||
|
is-directory,
|
||||||
|
/// Too many levels of symbolic links, similar to `ELOOP` in POSIX.
|
||||||
|
loop,
|
||||||
|
/// Too many links, similar to `EMLINK` in POSIX.
|
||||||
|
too-many-links,
|
||||||
|
/// Message too large, similar to `EMSGSIZE` in POSIX.
|
||||||
|
message-size,
|
||||||
|
/// Filename too long, similar to `ENAMETOOLONG` in POSIX.
|
||||||
|
name-too-long,
|
||||||
|
/// No such device, similar to `ENODEV` in POSIX.
|
||||||
|
no-device,
|
||||||
|
/// No such file or directory, similar to `ENOENT` in POSIX.
|
||||||
|
no-entry,
|
||||||
|
/// No locks available, similar to `ENOLCK` in POSIX.
|
||||||
|
no-lock,
|
||||||
|
/// Not enough space, similar to `ENOMEM` in POSIX.
|
||||||
|
insufficient-memory,
|
||||||
|
/// No space left on device, similar to `ENOSPC` in POSIX.
|
||||||
|
insufficient-space,
|
||||||
|
/// Not a directory or a symbolic link to a directory, similar to `ENOTDIR` in POSIX.
|
||||||
|
not-directory,
|
||||||
|
/// Directory not empty, similar to `ENOTEMPTY` in POSIX.
|
||||||
|
not-empty,
|
||||||
|
/// State not recoverable, similar to `ENOTRECOVERABLE` in POSIX.
|
||||||
|
not-recoverable,
|
||||||
|
/// Not supported, similar to `ENOTSUP` and `ENOSYS` in POSIX.
|
||||||
|
unsupported,
|
||||||
|
/// Inappropriate I/O control operation, similar to `ENOTTY` in POSIX.
|
||||||
|
no-tty,
|
||||||
|
/// No such device or address, similar to `ENXIO` in POSIX.
|
||||||
|
no-such-device,
|
||||||
|
/// Value too large to be stored in data type, similar to `EOVERFLOW` in POSIX.
|
||||||
|
overflow,
|
||||||
|
/// Operation not permitted, similar to `EPERM` in POSIX.
|
||||||
|
not-permitted,
|
||||||
|
/// Broken pipe, similar to `EPIPE` in POSIX.
|
||||||
|
pipe,
|
||||||
|
/// Read-only file system, similar to `EROFS` in POSIX.
|
||||||
|
read-only,
|
||||||
|
/// Invalid seek, similar to `ESPIPE` in POSIX.
|
||||||
|
invalid-seek,
|
||||||
|
/// Text file busy, similar to `ETXTBSY` in POSIX.
|
||||||
|
text-file-busy,
|
||||||
|
/// Cross-device link, similar to `EXDEV` in POSIX.
|
||||||
|
cross-device,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// File or memory access pattern advisory information.
|
||||||
|
enum advice {
|
||||||
|
/// The application has no advice to give on its behavior with respect
|
||||||
|
/// to the specified data.
|
||||||
|
normal,
|
||||||
|
/// The application expects to access the specified data sequentially
|
||||||
|
/// from lower offsets to higher offsets.
|
||||||
|
sequential,
|
||||||
|
/// The application expects to access the specified data in a random
|
||||||
|
/// order.
|
||||||
|
random,
|
||||||
|
/// The application expects to access the specified data in the near
|
||||||
|
/// future.
|
||||||
|
will-need,
|
||||||
|
/// The application expects that it will not access the specified data
|
||||||
|
/// in the near future.
|
||||||
|
dont-need,
|
||||||
|
/// The application expects to access the specified data once and then
|
||||||
|
/// not reuse it thereafter.
|
||||||
|
no-reuse,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A 128-bit hash value, split into parts because wasm doesn't have a
|
||||||
|
/// 128-bit integer type.
|
||||||
|
record metadata-hash-value {
|
||||||
|
/// 64 bits of a 128-bit hash value.
|
||||||
|
lower: u64,
|
||||||
|
/// Another 64 bits of a 128-bit hash value.
|
||||||
|
upper: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A descriptor is a reference to a filesystem object, which may be a file,
|
||||||
|
/// directory, named pipe, special file, or other object on which filesystem
|
||||||
|
/// calls may be made.
|
||||||
|
resource descriptor {
|
||||||
|
/// Return a stream for reading from a file, if available.
|
||||||
|
///
|
||||||
|
/// May fail with an error-code describing why the file cannot be read.
|
||||||
|
///
|
||||||
|
/// Multiple read, write, and append streams may be active on the same open
|
||||||
|
/// file and they do not interfere with each other.
|
||||||
|
///
|
||||||
|
/// Note: This allows using `read-stream`, which is similar to `read` in POSIX.
|
||||||
|
read-via-stream: func(
|
||||||
|
/// The offset within the file at which to start reading.
|
||||||
|
offset: filesize,
|
||||||
|
) -> result<input-stream, error-code>;
|
||||||
|
|
||||||
|
/// Return a stream for writing to a file, if available.
|
||||||
|
///
|
||||||
|
/// May fail with an error-code describing why the file cannot be written.
|
||||||
|
///
|
||||||
|
/// Note: This allows using `write-stream`, which is similar to `write` in
|
||||||
|
/// POSIX.
|
||||||
|
write-via-stream: func(
|
||||||
|
/// The offset within the file at which to start writing.
|
||||||
|
offset: filesize,
|
||||||
|
) -> result<output-stream, error-code>;
|
||||||
|
|
||||||
|
/// Return a stream for appending to a file, if available.
|
||||||
|
///
|
||||||
|
/// May fail with an error-code describing why the file cannot be appended.
|
||||||
|
///
|
||||||
|
/// Note: This allows using `write-stream`, which is similar to `write` with
|
||||||
|
/// `O_APPEND` in in POSIX.
|
||||||
|
append-via-stream: func() -> result<output-stream, error-code>;
|
||||||
|
|
||||||
|
/// Provide file advisory information on a descriptor.
|
||||||
|
///
|
||||||
|
/// This is similar to `posix_fadvise` in POSIX.
|
||||||
|
advise: func(
|
||||||
|
/// The offset within the file to which the advisory applies.
|
||||||
|
offset: filesize,
|
||||||
|
/// The length of the region to which the advisory applies.
|
||||||
|
length: filesize,
|
||||||
|
/// The advice.
|
||||||
|
advice: advice
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Synchronize the data of a file to disk.
|
||||||
|
///
|
||||||
|
/// This function succeeds with no effect if the file descriptor is not
|
||||||
|
/// opened for writing.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `fdatasync` in POSIX.
|
||||||
|
sync-data: func() -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Get flags associated with a descriptor.
|
||||||
|
///
|
||||||
|
/// Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX.
|
||||||
|
///
|
||||||
|
/// Note: This returns the value that was the `fs_flags` value returned
|
||||||
|
/// from `fdstat_get` in earlier versions of WASI.
|
||||||
|
get-flags: func() -> result<descriptor-flags, error-code>;
|
||||||
|
|
||||||
|
/// Get the dynamic type of a descriptor.
|
||||||
|
///
|
||||||
|
/// Note: This returns the same value as the `type` field of the `fd-stat`
|
||||||
|
/// returned by `stat`, `stat-at` and similar.
|
||||||
|
///
|
||||||
|
/// Note: This returns similar flags to the `st_mode & S_IFMT` value provided
|
||||||
|
/// by `fstat` in POSIX.
|
||||||
|
///
|
||||||
|
/// Note: This returns the value that was the `fs_filetype` value returned
|
||||||
|
/// from `fdstat_get` in earlier versions of WASI.
|
||||||
|
get-type: func() -> result<descriptor-type, error-code>;
|
||||||
|
|
||||||
|
/// Adjust the size of an open file. If this increases the file's size, the
|
||||||
|
/// extra bytes are filled with zeros.
|
||||||
|
///
|
||||||
|
/// Note: This was called `fd_filestat_set_size` in earlier versions of WASI.
|
||||||
|
set-size: func(size: filesize) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Adjust the timestamps of an open file or directory.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `futimens` in POSIX.
|
||||||
|
///
|
||||||
|
/// Note: This was called `fd_filestat_set_times` in earlier versions of WASI.
|
||||||
|
set-times: func(
|
||||||
|
/// The desired values of the data access timestamp.
|
||||||
|
data-access-timestamp: new-timestamp,
|
||||||
|
/// The desired values of the data modification timestamp.
|
||||||
|
data-modification-timestamp: new-timestamp,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Read from a descriptor, without using and updating the descriptor's offset.
|
||||||
|
///
|
||||||
|
/// This function returns a list of bytes containing the data that was
|
||||||
|
/// read, along with a bool which, when true, indicates that the end of the
|
||||||
|
/// file was reached. The returned list will contain up to `length` bytes; it
|
||||||
|
/// may return fewer than requested, if the end of the file is reached or
|
||||||
|
/// if the I/O operation is interrupted.
|
||||||
|
///
|
||||||
|
/// In the future, this may change to return a `stream<u8, error-code>`.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `pread` in POSIX.
|
||||||
|
read: func(
|
||||||
|
/// The maximum number of bytes to read.
|
||||||
|
length: filesize,
|
||||||
|
/// The offset within the file at which to read.
|
||||||
|
offset: filesize,
|
||||||
|
) -> result<tuple<list<u8>, bool>, error-code>;
|
||||||
|
|
||||||
|
/// Write to a descriptor, without using and updating the descriptor's offset.
|
||||||
|
///
|
||||||
|
/// It is valid to write past the end of a file; the file is extended to the
|
||||||
|
/// extent of the write, with bytes between the previous end and the start of
|
||||||
|
/// the write set to zero.
|
||||||
|
///
|
||||||
|
/// In the future, this may change to take a `stream<u8, error-code>`.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `pwrite` in POSIX.
|
||||||
|
write: func(
|
||||||
|
/// Data to write
|
||||||
|
buffer: list<u8>,
|
||||||
|
/// The offset within the file at which to write.
|
||||||
|
offset: filesize,
|
||||||
|
) -> result<filesize, error-code>;
|
||||||
|
|
||||||
|
/// Read directory entries from a directory.
|
||||||
|
///
|
||||||
|
/// On filesystems where directories contain entries referring to themselves
|
||||||
|
/// and their parents, often named `.` and `..` respectively, these entries
|
||||||
|
/// are omitted.
|
||||||
|
///
|
||||||
|
/// This always returns a new stream which starts at the beginning of the
|
||||||
|
/// directory. Multiple streams may be active on the same directory, and they
|
||||||
|
/// do not interfere with each other.
|
||||||
|
read-directory: func() -> result<directory-entry-stream, error-code>;
|
||||||
|
|
||||||
|
/// Synchronize the data and metadata of a file to disk.
|
||||||
|
///
|
||||||
|
/// This function succeeds with no effect if the file descriptor is not
|
||||||
|
/// opened for writing.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `fsync` in POSIX.
|
||||||
|
sync: func() -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Create a directory.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `mkdirat` in POSIX.
|
||||||
|
create-directory-at: func(
|
||||||
|
/// The relative path at which to create the directory.
|
||||||
|
path: string,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Return the attributes of an open file or directory.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `fstat` in POSIX, except that it does not return
|
||||||
|
/// device and inode information. For testing whether two descriptors refer to
|
||||||
|
/// the same underlying filesystem object, use `is-same-object`. To obtain
|
||||||
|
/// additional data that can be used do determine whether a file has been
|
||||||
|
/// modified, use `metadata-hash`.
|
||||||
|
///
|
||||||
|
/// Note: This was called `fd_filestat_get` in earlier versions of WASI.
|
||||||
|
stat: func() -> result<descriptor-stat, error-code>;
|
||||||
|
|
||||||
|
/// Return the attributes of a file or directory.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `fstatat` in POSIX, except that it does not
|
||||||
|
/// return device and inode information. See the `stat` description for a
|
||||||
|
/// discussion of alternatives.
|
||||||
|
///
|
||||||
|
/// Note: This was called `path_filestat_get` in earlier versions of WASI.
|
||||||
|
stat-at: func(
|
||||||
|
/// Flags determining the method of how the path is resolved.
|
||||||
|
path-flags: path-flags,
|
||||||
|
/// The relative path of the file or directory to inspect.
|
||||||
|
path: string,
|
||||||
|
) -> result<descriptor-stat, error-code>;
|
||||||
|
|
||||||
|
/// Adjust the timestamps of a file or directory.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `utimensat` in POSIX.
|
||||||
|
///
|
||||||
|
/// Note: This was called `path_filestat_set_times` in earlier versions of
|
||||||
|
/// WASI.
|
||||||
|
set-times-at: func(
|
||||||
|
/// Flags determining the method of how the path is resolved.
|
||||||
|
path-flags: path-flags,
|
||||||
|
/// The relative path of the file or directory to operate on.
|
||||||
|
path: string,
|
||||||
|
/// The desired values of the data access timestamp.
|
||||||
|
data-access-timestamp: new-timestamp,
|
||||||
|
/// The desired values of the data modification timestamp.
|
||||||
|
data-modification-timestamp: new-timestamp,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Create a hard link.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `linkat` in POSIX.
|
||||||
|
link-at: func(
|
||||||
|
/// Flags determining the method of how the path is resolved.
|
||||||
|
old-path-flags: path-flags,
|
||||||
|
/// The relative source path from which to link.
|
||||||
|
old-path: string,
|
||||||
|
/// The base directory for `new-path`.
|
||||||
|
new-descriptor: borrow<descriptor>,
|
||||||
|
/// The relative destination path at which to create the hard link.
|
||||||
|
new-path: string,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Open a file or directory.
|
||||||
|
///
|
||||||
|
/// The returned descriptor is not guaranteed to be the lowest-numbered
|
||||||
|
/// descriptor not currently open/ it is randomized to prevent applications
|
||||||
|
/// from depending on making assumptions about indexes, since this is
|
||||||
|
/// error-prone in multi-threaded contexts. The returned descriptor is
|
||||||
|
/// guaranteed to be less than 2**31.
|
||||||
|
///
|
||||||
|
/// If `flags` contains `descriptor-flags::mutate-directory`, and the base
|
||||||
|
/// descriptor doesn't have `descriptor-flags::mutate-directory` set,
|
||||||
|
/// `open-at` fails with `error-code::read-only`.
|
||||||
|
///
|
||||||
|
/// If `flags` contains `write` or `mutate-directory`, or `open-flags`
|
||||||
|
/// contains `truncate` or `create`, and the base descriptor doesn't have
|
||||||
|
/// `descriptor-flags::mutate-directory` set, `open-at` fails with
|
||||||
|
/// `error-code::read-only`.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `openat` in POSIX.
|
||||||
|
open-at: func(
|
||||||
|
/// Flags determining the method of how the path is resolved.
|
||||||
|
path-flags: path-flags,
|
||||||
|
/// The relative path of the object to open.
|
||||||
|
path: string,
|
||||||
|
/// The method by which to open the file.
|
||||||
|
open-flags: open-flags,
|
||||||
|
/// Flags to use for the resulting descriptor.
|
||||||
|
%flags: descriptor-flags,
|
||||||
|
) -> result<descriptor, error-code>;
|
||||||
|
|
||||||
|
/// Read the contents of a symbolic link.
|
||||||
|
///
|
||||||
|
/// If the contents contain an absolute or rooted path in the underlying
|
||||||
|
/// filesystem, this function fails with `error-code::not-permitted`.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `readlinkat` in POSIX.
|
||||||
|
readlink-at: func(
|
||||||
|
/// The relative path of the symbolic link from which to read.
|
||||||
|
path: string,
|
||||||
|
) -> result<string, error-code>;
|
||||||
|
|
||||||
|
/// Remove a directory.
|
||||||
|
///
|
||||||
|
/// Return `error-code::not-empty` if the directory is not empty.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
|
||||||
|
remove-directory-at: func(
|
||||||
|
/// The relative path to a directory to remove.
|
||||||
|
path: string,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Rename a filesystem object.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `renameat` in POSIX.
|
||||||
|
rename-at: func(
|
||||||
|
/// The relative source path of the file or directory to rename.
|
||||||
|
old-path: string,
|
||||||
|
/// The base directory for `new-path`.
|
||||||
|
new-descriptor: borrow<descriptor>,
|
||||||
|
/// The relative destination path to which to rename the file or directory.
|
||||||
|
new-path: string,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Create a symbolic link (also known as a "symlink").
|
||||||
|
///
|
||||||
|
/// If `old-path` starts with `/`, the function fails with
|
||||||
|
/// `error-code::not-permitted`.
|
||||||
|
///
|
||||||
|
/// Note: This is similar to `symlinkat` in POSIX.
|
||||||
|
symlink-at: func(
|
||||||
|
/// The contents of the symbolic link.
|
||||||
|
old-path: string,
|
||||||
|
/// The relative destination path at which to create the symbolic link.
|
||||||
|
new-path: string,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Unlink a filesystem object that is not a directory.
|
||||||
|
///
|
||||||
|
/// Return `error-code::is-directory` if the path refers to a directory.
|
||||||
|
/// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
|
||||||
|
unlink-file-at: func(
|
||||||
|
/// The relative path to a file to unlink.
|
||||||
|
path: string,
|
||||||
|
) -> result<_, error-code>;
|
||||||
|
|
||||||
|
/// Test whether two descriptors refer to the same filesystem object.
|
||||||
|
///
|
||||||
|
/// In POSIX, this corresponds to testing whether the two descriptors have the
|
||||||
|
/// same device (`st_dev`) and inode (`st_ino` or `d_ino`) numbers.
|
||||||
|
/// wasi-filesystem does not expose device and inode numbers, so this function
|
||||||
|
/// may be used instead.
|
||||||
|
is-same-object: func(other: borrow<descriptor>) -> bool;
|
||||||
|
|
||||||
|
/// Return a hash of the metadata associated with a filesystem object referred
|
||||||
|
/// to by a descriptor.
|
||||||
|
///
|
||||||
|
/// This returns a hash of the last-modification timestamp and file size, and
|
||||||
|
/// may also include the inode number, device number, birth timestamp, and
|
||||||
|
/// other metadata fields that may change when the file is modified or
|
||||||
|
/// replaced. It may also include a secret value chosen by the
|
||||||
|
/// implementation and not otherwise exposed.
|
||||||
|
///
|
||||||
|
/// Implementations are encourated to provide the following properties:
|
||||||
|
///
|
||||||
|
/// - If the file is not modified or replaced, the computed hash value should
|
||||||
|
/// usually not change.
|
||||||
|
/// - If the object is modified or replaced, the computed hash value should
|
||||||
|
/// usually change.
|
||||||
|
/// - The inputs to the hash should not be easily computable from the
|
||||||
|
/// computed hash.
|
||||||
|
///
|
||||||
|
/// However, none of these is required.
|
||||||
|
metadata-hash: func() -> result<metadata-hash-value, error-code>;
|
||||||
|
|
||||||
|
/// Return a hash of the metadata associated with a filesystem object referred
|
||||||
|
/// to by a directory descriptor and a relative path.
|
||||||
|
///
|
||||||
|
/// This performs the same hash computation as `metadata-hash`.
|
||||||
|
metadata-hash-at: func(
|
||||||
|
/// Flags determining the method of how the path is resolved.
|
||||||
|
path-flags: path-flags,
|
||||||
|
/// The relative path of the file or directory to inspect.
|
||||||
|
path: string,
|
||||||
|
) -> result<metadata-hash-value, error-code>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A stream of directory entries.
|
||||||
|
resource directory-entry-stream {
|
||||||
|
/// Read a single directory entry from a `directory-entry-stream`.
|
||||||
|
read-directory-entry: func() -> result<option<directory-entry>, error-code>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to extract a filesystem-related `error-code` from the stream
|
||||||
|
/// `error` provided.
|
||||||
|
///
|
||||||
|
/// Stream operations which return `stream-error::last-operation-failed`
|
||||||
|
/// have a payload with more information about the operation that failed.
|
||||||
|
/// This payload can be passed through to this function to see if there's
|
||||||
|
/// filesystem-related information about the error to return.
|
||||||
|
///
|
||||||
|
/// Note that this function is fallible because not all stream-related
|
||||||
|
/// errors are filesystem-related errors.
|
||||||
|
filesystem-error-code: func(err: borrow<error>) -> option<error-code>;
|
||||||
|
}
|
||||||
6
crates/wasi_fs/wit/deps/filesystem/world.wit
Normal file
6
crates/wasi_fs/wit/deps/filesystem/world.wit
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package wasi:filesystem@0.2.0;
|
||||||
|
|
||||||
|
world imports {
|
||||||
|
import types;
|
||||||
|
import preopens;
|
||||||
|
}
|
||||||
34
crates/wasi_fs/wit/deps/io/error.wit
Normal file
34
crates/wasi_fs/wit/deps/io/error.wit
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package wasi:io@0.2.0;
|
||||||
|
|
||||||
|
|
||||||
|
interface error {
|
||||||
|
/// A resource which represents some error information.
|
||||||
|
///
|
||||||
|
/// The only method provided by this resource is `to-debug-string`,
|
||||||
|
/// which provides some human-readable information about the error.
|
||||||
|
///
|
||||||
|
/// In the `wasi:io` package, this resource is returned through the
|
||||||
|
/// `wasi:io/streams/stream-error` type.
|
||||||
|
///
|
||||||
|
/// To provide more specific error information, other interfaces may
|
||||||
|
/// provide functions to further "downcast" this error into more specific
|
||||||
|
/// error information. For example, `error`s returned in streams derived
|
||||||
|
/// from filesystem types to be described using the filesystem's own
|
||||||
|
/// error-code type, using the function
|
||||||
|
/// `wasi:filesystem/types/filesystem-error-code`, which takes a parameter
|
||||||
|
/// `borrow<error>` and returns
|
||||||
|
/// `option<wasi:filesystem/types/error-code>`.
|
||||||
|
///
|
||||||
|
/// The set of functions which can "downcast" an `error` into a more
|
||||||
|
/// concrete type is open.
|
||||||
|
resource error {
|
||||||
|
/// Returns a string that is suitable to assist humans in debugging
|
||||||
|
/// this error.
|
||||||
|
///
|
||||||
|
/// WARNING: The returned string should not be consumed mechanically!
|
||||||
|
/// It may change across platforms, hosts, or other implementation
|
||||||
|
/// details. Parsing this string is a major platform-compatibility
|
||||||
|
/// hazard.
|
||||||
|
to-debug-string: func() -> string;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
crates/wasi_fs/wit/deps/io/poll.wit
Normal file
41
crates/wasi_fs/wit/deps/io/poll.wit
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package wasi:io@0.2.0;
|
||||||
|
|
||||||
|
/// A poll API intended to let users wait for I/O events on multiple handles
|
||||||
|
/// at once.
|
||||||
|
interface poll {
|
||||||
|
/// `pollable` represents a single I/O event which may be ready, or not.
|
||||||
|
resource pollable {
|
||||||
|
|
||||||
|
/// Return the readiness of a pollable. This function never blocks.
|
||||||
|
///
|
||||||
|
/// Returns `true` when the pollable is ready, and `false` otherwise.
|
||||||
|
ready: func() -> bool;
|
||||||
|
|
||||||
|
/// `block` returns immediately if the pollable is ready, and otherwise
|
||||||
|
/// blocks until ready.
|
||||||
|
///
|
||||||
|
/// This function is equivalent to calling `poll.poll` on a list
|
||||||
|
/// containing only this pollable.
|
||||||
|
block: func();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Poll for completion on a set of pollables.
|
||||||
|
///
|
||||||
|
/// This function takes a list of pollables, which identify I/O sources of
|
||||||
|
/// interest, and waits until one or more of the events is ready for I/O.
|
||||||
|
///
|
||||||
|
/// The result `list<u32>` contains one or more indices of handles in the
|
||||||
|
/// argument list that is ready for I/O.
|
||||||
|
///
|
||||||
|
/// If the list contains more elements than can be indexed with a `u32`
|
||||||
|
/// value, this function traps.
|
||||||
|
///
|
||||||
|
/// A timeout can be implemented by adding a pollable from the
|
||||||
|
/// wasi-clocks API to the list.
|
||||||
|
///
|
||||||
|
/// This function does not return a `result`; polling in itself does not
|
||||||
|
/// do any I/O so it doesn't fail. If any of the I/O sources identified by
|
||||||
|
/// the pollables has an error, it is indicated by marking the source as
|
||||||
|
/// being reaedy for I/O.
|
||||||
|
poll: func(in: list<borrow<pollable>>) -> list<u32>;
|
||||||
|
}
|
||||||
262
crates/wasi_fs/wit/deps/io/streams.wit
Normal file
262
crates/wasi_fs/wit/deps/io/streams.wit
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
package wasi:io@0.2.0;
|
||||||
|
|
||||||
|
/// WASI I/O is an I/O abstraction API which is currently focused on providing
|
||||||
|
/// stream types.
|
||||||
|
///
|
||||||
|
/// In the future, the component model is expected to add built-in stream types;
|
||||||
|
/// when it does, they are expected to subsume this API.
|
||||||
|
interface streams {
|
||||||
|
use error.{error};
|
||||||
|
use poll.{pollable};
|
||||||
|
|
||||||
|
/// An error for input-stream and output-stream operations.
|
||||||
|
variant stream-error {
|
||||||
|
/// The last operation (a write or flush) failed before completion.
|
||||||
|
///
|
||||||
|
/// More information is available in the `error` payload.
|
||||||
|
last-operation-failed(error),
|
||||||
|
/// The stream is closed: no more input will be accepted by the
|
||||||
|
/// stream. A closed output-stream will return this error on all
|
||||||
|
/// future operations.
|
||||||
|
closed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An input bytestream.
|
||||||
|
///
|
||||||
|
/// `input-stream`s are *non-blocking* to the extent practical on underlying
|
||||||
|
/// platforms. I/O operations always return promptly; if fewer bytes are
|
||||||
|
/// promptly available than requested, they return the number of bytes promptly
|
||||||
|
/// available, which could even be zero. To wait for data to be available,
|
||||||
|
/// use the `subscribe` function to obtain a `pollable` which can be polled
|
||||||
|
/// for using `wasi:io/poll`.
|
||||||
|
resource input-stream {
|
||||||
|
/// Perform a non-blocking read from the stream.
|
||||||
|
///
|
||||||
|
/// When the source of a `read` is binary data, the bytes from the source
|
||||||
|
/// are returned verbatim. When the source of a `read` is known to the
|
||||||
|
/// implementation to be text, bytes containing the UTF-8 encoding of the
|
||||||
|
/// text are returned.
|
||||||
|
///
|
||||||
|
/// This function returns a list of bytes containing the read data,
|
||||||
|
/// when successful. The returned list will contain up to `len` bytes;
|
||||||
|
/// it may return fewer than requested, but not more. The list is
|
||||||
|
/// empty when no bytes are available for reading at this time. The
|
||||||
|
/// pollable given by `subscribe` will be ready when more bytes are
|
||||||
|
/// available.
|
||||||
|
///
|
||||||
|
/// This function fails with a `stream-error` when the operation
|
||||||
|
/// encounters an error, giving `last-operation-failed`, or when the
|
||||||
|
/// stream is closed, giving `closed`.
|
||||||
|
///
|
||||||
|
/// When the caller gives a `len` of 0, it represents a request to
|
||||||
|
/// read 0 bytes. If the stream is still open, this call should
|
||||||
|
/// succeed and return an empty list, or otherwise fail with `closed`.
|
||||||
|
///
|
||||||
|
/// The `len` parameter is a `u64`, which could represent a list of u8 which
|
||||||
|
/// is not possible to allocate in wasm32, or not desirable to allocate as
|
||||||
|
/// as a return value by the callee. The callee may return a list of bytes
|
||||||
|
/// less than `len` in size while more bytes are available for reading.
|
||||||
|
read: func(
|
||||||
|
/// The maximum number of bytes to read
|
||||||
|
len: u64
|
||||||
|
) -> result<list<u8>, stream-error>;
|
||||||
|
|
||||||
|
/// Read bytes from a stream, after blocking until at least one byte can
|
||||||
|
/// be read. Except for blocking, behavior is identical to `read`.
|
||||||
|
blocking-read: func(
|
||||||
|
/// The maximum number of bytes to read
|
||||||
|
len: u64
|
||||||
|
) -> result<list<u8>, stream-error>;
|
||||||
|
|
||||||
|
/// Skip bytes from a stream. Returns number of bytes skipped.
|
||||||
|
///
|
||||||
|
/// Behaves identical to `read`, except instead of returning a list
|
||||||
|
/// of bytes, returns the number of bytes consumed from the stream.
|
||||||
|
skip: func(
|
||||||
|
/// The maximum number of bytes to skip.
|
||||||
|
len: u64,
|
||||||
|
) -> result<u64, stream-error>;
|
||||||
|
|
||||||
|
/// Skip bytes from a stream, after blocking until at least one byte
|
||||||
|
/// can be skipped. Except for blocking behavior, identical to `skip`.
|
||||||
|
blocking-skip: func(
|
||||||
|
/// The maximum number of bytes to skip.
|
||||||
|
len: u64,
|
||||||
|
) -> result<u64, stream-error>;
|
||||||
|
|
||||||
|
/// Create a `pollable` which will resolve once either the specified stream
|
||||||
|
/// has bytes available to read or the other end of the stream has been
|
||||||
|
/// closed.
|
||||||
|
/// The created `pollable` is a child resource of the `input-stream`.
|
||||||
|
/// Implementations may trap if the `input-stream` is dropped before
|
||||||
|
/// all derived `pollable`s created with this function are dropped.
|
||||||
|
subscribe: func() -> pollable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// An output bytestream.
|
||||||
|
///
|
||||||
|
/// `output-stream`s are *non-blocking* to the extent practical on
|
||||||
|
/// underlying platforms. Except where specified otherwise, I/O operations also
|
||||||
|
/// always return promptly, after the number of bytes that can be written
|
||||||
|
/// promptly, which could even be zero. To wait for the stream to be ready to
|
||||||
|
/// accept data, the `subscribe` function to obtain a `pollable` which can be
|
||||||
|
/// polled for using `wasi:io/poll`.
|
||||||
|
resource output-stream {
|
||||||
|
/// Check readiness for writing. This function never blocks.
|
||||||
|
///
|
||||||
|
/// Returns the number of bytes permitted for the next call to `write`,
|
||||||
|
/// or an error. Calling `write` with more bytes than this function has
|
||||||
|
/// permitted will trap.
|
||||||
|
///
|
||||||
|
/// When this function returns 0 bytes, the `subscribe` pollable will
|
||||||
|
/// become ready when this function will report at least 1 byte, or an
|
||||||
|
/// error.
|
||||||
|
check-write: func() -> result<u64, stream-error>;
|
||||||
|
|
||||||
|
/// Perform a write. This function never blocks.
|
||||||
|
///
|
||||||
|
/// When the destination of a `write` is binary data, the bytes from
|
||||||
|
/// `contents` are written verbatim. When the destination of a `write` is
|
||||||
|
/// known to the implementation to be text, the bytes of `contents` are
|
||||||
|
/// transcoded from UTF-8 into the encoding of the destination and then
|
||||||
|
/// written.
|
||||||
|
///
|
||||||
|
/// Precondition: check-write gave permit of Ok(n) and contents has a
|
||||||
|
/// length of less than or equal to n. Otherwise, this function will trap.
|
||||||
|
///
|
||||||
|
/// returns Err(closed) without writing if the stream has closed since
|
||||||
|
/// the last call to check-write provided a permit.
|
||||||
|
write: func(
|
||||||
|
contents: list<u8>
|
||||||
|
) -> result<_, stream-error>;
|
||||||
|
|
||||||
|
/// Perform a write of up to 4096 bytes, and then flush the stream. Block
|
||||||
|
/// until all of these operations are complete, or an error occurs.
|
||||||
|
///
|
||||||
|
/// This is a convenience wrapper around the use of `check-write`,
|
||||||
|
/// `subscribe`, `write`, and `flush`, and is implemented with the
|
||||||
|
/// following pseudo-code:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// let pollable = this.subscribe();
|
||||||
|
/// while !contents.is_empty() {
|
||||||
|
/// // Wait for the stream to become writable
|
||||||
|
/// pollable.block();
|
||||||
|
/// let Ok(n) = this.check-write(); // eliding error handling
|
||||||
|
/// let len = min(n, contents.len());
|
||||||
|
/// let (chunk, rest) = contents.split_at(len);
|
||||||
|
/// this.write(chunk ); // eliding error handling
|
||||||
|
/// contents = rest;
|
||||||
|
/// }
|
||||||
|
/// this.flush();
|
||||||
|
/// // Wait for completion of `flush`
|
||||||
|
/// pollable.block();
|
||||||
|
/// // Check for any errors that arose during `flush`
|
||||||
|
/// let _ = this.check-write(); // eliding error handling
|
||||||
|
/// ```
|
||||||
|
blocking-write-and-flush: func(
|
||||||
|
contents: list<u8>
|
||||||
|
) -> result<_, stream-error>;
|
||||||
|
|
||||||
|
/// Request to flush buffered output. This function never blocks.
|
||||||
|
///
|
||||||
|
/// This tells the output-stream that the caller intends any buffered
|
||||||
|
/// output to be flushed. the output which is expected to be flushed
|
||||||
|
/// is all that has been passed to `write` prior to this call.
|
||||||
|
///
|
||||||
|
/// Upon calling this function, the `output-stream` will not accept any
|
||||||
|
/// writes (`check-write` will return `ok(0)`) until the flush has
|
||||||
|
/// completed. The `subscribe` pollable will become ready when the
|
||||||
|
/// flush has completed and the stream can accept more writes.
|
||||||
|
flush: func() -> result<_, stream-error>;
|
||||||
|
|
||||||
|
/// Request to flush buffered output, and block until flush completes
|
||||||
|
/// and stream is ready for writing again.
|
||||||
|
blocking-flush: func() -> result<_, stream-error>;
|
||||||
|
|
||||||
|
/// Create a `pollable` which will resolve once the output-stream
|
||||||
|
/// is ready for more writing, or an error has occured. When this
|
||||||
|
/// pollable is ready, `check-write` will return `ok(n)` with n>0, or an
|
||||||
|
/// error.
|
||||||
|
///
|
||||||
|
/// If the stream is closed, this pollable is always ready immediately.
|
||||||
|
///
|
||||||
|
/// The created `pollable` is a child resource of the `output-stream`.
|
||||||
|
/// Implementations may trap if the `output-stream` is dropped before
|
||||||
|
/// all derived `pollable`s created with this function are dropped.
|
||||||
|
subscribe: func() -> pollable;
|
||||||
|
|
||||||
|
/// Write zeroes to a stream.
|
||||||
|
///
|
||||||
|
/// This should be used precisely like `write` with the exact same
|
||||||
|
/// preconditions (must use check-write first), but instead of
|
||||||
|
/// passing a list of bytes, you simply pass the number of zero-bytes
|
||||||
|
/// that should be written.
|
||||||
|
write-zeroes: func(
|
||||||
|
/// The number of zero-bytes to write
|
||||||
|
len: u64
|
||||||
|
) -> result<_, stream-error>;
|
||||||
|
|
||||||
|
/// Perform a write of up to 4096 zeroes, and then flush the stream.
|
||||||
|
/// Block until all of these operations are complete, or an error
|
||||||
|
/// occurs.
|
||||||
|
///
|
||||||
|
/// This is a convenience wrapper around the use of `check-write`,
|
||||||
|
/// `subscribe`, `write-zeroes`, and `flush`, and is implemented with
|
||||||
|
/// the following pseudo-code:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// let pollable = this.subscribe();
|
||||||
|
/// while num_zeroes != 0 {
|
||||||
|
/// // Wait for the stream to become writable
|
||||||
|
/// pollable.block();
|
||||||
|
/// let Ok(n) = this.check-write(); // eliding error handling
|
||||||
|
/// let len = min(n, num_zeroes);
|
||||||
|
/// this.write-zeroes(len); // eliding error handling
|
||||||
|
/// num_zeroes -= len;
|
||||||
|
/// }
|
||||||
|
/// this.flush();
|
||||||
|
/// // Wait for completion of `flush`
|
||||||
|
/// pollable.block();
|
||||||
|
/// // Check for any errors that arose during `flush`
|
||||||
|
/// let _ = this.check-write(); // eliding error handling
|
||||||
|
/// ```
|
||||||
|
blocking-write-zeroes-and-flush: func(
|
||||||
|
/// The number of zero-bytes to write
|
||||||
|
len: u64
|
||||||
|
) -> result<_, stream-error>;
|
||||||
|
|
||||||
|
/// Read from one stream and write to another.
|
||||||
|
///
|
||||||
|
/// The behavior of splice is equivelant to:
|
||||||
|
/// 1. calling `check-write` on the `output-stream`
|
||||||
|
/// 2. calling `read` on the `input-stream` with the smaller of the
|
||||||
|
/// `check-write` permitted length and the `len` provided to `splice`
|
||||||
|
/// 3. calling `write` on the `output-stream` with that read data.
|
||||||
|
///
|
||||||
|
/// Any error reported by the call to `check-write`, `read`, or
|
||||||
|
/// `write` ends the splice and reports that error.
|
||||||
|
///
|
||||||
|
/// This function returns the number of bytes transferred; it may be less
|
||||||
|
/// than `len`.
|
||||||
|
splice: func(
|
||||||
|
/// The stream to read from
|
||||||
|
src: borrow<input-stream>,
|
||||||
|
/// The number of bytes to splice
|
||||||
|
len: u64,
|
||||||
|
) -> result<u64, stream-error>;
|
||||||
|
|
||||||
|
/// Read from one stream and write to another, with blocking.
|
||||||
|
///
|
||||||
|
/// This is similar to `splice`, except that it blocks until the
|
||||||
|
/// `output-stream` is ready for writing, and the `input-stream`
|
||||||
|
/// is ready for reading, before performing the `splice`.
|
||||||
|
blocking-splice: func(
|
||||||
|
/// The stream to read from
|
||||||
|
src: borrow<input-stream>,
|
||||||
|
/// The number of bytes to splice
|
||||||
|
len: u64,
|
||||||
|
) -> result<u64, stream-error>;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
crates/wasi_fs/wit/deps/io/world.wit
Normal file
6
crates/wasi_fs/wit/deps/io/world.wit
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package wasi:io@0.2.0;
|
||||||
|
|
||||||
|
world imports {
|
||||||
|
import streams;
|
||||||
|
import poll;
|
||||||
|
}
|
||||||
1
crates/wasi_fs/wit/wasi.wit
Normal file
1
crates/wasi_fs/wit/wasi.wit
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package wasmtime:wasi;
|
||||||
Reference in New Issue
Block a user