wasmtime_wasi/p3/filesystem/
mod.rs

1mod host;
2
3use crate::TrappableError;
4use crate::filesystem::{WasiFilesystem, WasiFilesystemView};
5use crate::p3::bindings::filesystem::{preopens, types};
6use wasmtime::component::Linker;
7
8pub type FilesystemResult<T> = Result<T, FilesystemError>;
9pub type FilesystemError = TrappableError<types::ErrorCode>;
10
11/// Add all WASI interfaces from this module into the `linker` provided.
12///
13/// This function will add all interfaces implemented by this module to the
14/// [`Linker`], which corresponds to the `wasi:filesystem/imports` world supported by
15/// this module.
16///
17/// This is low-level API for advanced use cases,
18/// [`wasmtime_wasi::p3::add_to_linker`](crate::p3::add_to_linker) can be used instead
19/// to add *all* wasip3 interfaces (including the ones from this module) to the `linker`.
20///
21/// # Example
22///
23/// ```
24/// use wasmtime::{Engine, Result, Store, Config};
25/// use wasmtime::component::{Linker, ResourceTable};
26/// use wasmtime_wasi::filesystem::{WasiFilesystemCtx, WasiFilesystemCtxView, WasiFilesystemView};
27///
28/// fn main() -> Result<()> {
29///     let mut config = Config::new();
30///     config.async_support(true);
31///     config.wasm_component_model_async(true);
32///     let engine = Engine::new(&config)?;
33///
34///     let mut linker = Linker::<MyState>::new(&engine);
35///     wasmtime_wasi::p3::filesystem::add_to_linker(&mut linker)?;
36///     // ... add any further functionality to `linker` if desired ...
37///
38///     let mut store = Store::new(
39///         &engine,
40///         MyState::default(),
41///     );
42///
43///     // ... use `linker` to instantiate within `store` ...
44///
45///     Ok(())
46/// }
47///
48/// #[derive(Default)]
49/// struct MyState {
50///     filesystem: WasiFilesystemCtx,
51///     table: ResourceTable,
52/// }
53///
54/// impl WasiFilesystemView for MyState {
55///     fn filesystem(&mut self) -> WasiFilesystemCtxView<'_> {
56///         WasiFilesystemCtxView {
57///             ctx: &mut self.filesystem,
58///             table: &mut self.table,
59///         }
60///     }
61/// }
62/// ```
63pub fn add_to_linker<T>(linker: &mut Linker<T>) -> wasmtime::Result<()>
64where
65    T: WasiFilesystemView + 'static,
66{
67    types::add_to_linker::<_, WasiFilesystem>(linker, T::filesystem)?;
68    preopens::add_to_linker::<_, WasiFilesystem>(linker, T::filesystem)?;
69    Ok(())
70}
71
72impl<'a> From<&'a std::io::Error> for types::ErrorCode {
73    fn from(err: &'a std::io::Error) -> Self {
74        crate::filesystem::ErrorCode::from(err).into()
75    }
76}
77
78impl From<std::io::Error> for types::ErrorCode {
79    fn from(err: std::io::Error) -> Self {
80        Self::from(&err)
81    }
82}
83
84impl From<std::io::Error> for FilesystemError {
85    fn from(error: std::io::Error) -> Self {
86        types::ErrorCode::from(error).into()
87    }
88}
89
90impl From<crate::filesystem::ErrorCode> for types::ErrorCode {
91    fn from(error: crate::filesystem::ErrorCode) -> Self {
92        match error {
93            crate::filesystem::ErrorCode::Access => Self::Access,
94            crate::filesystem::ErrorCode::Already => Self::Already,
95            crate::filesystem::ErrorCode::BadDescriptor => Self::BadDescriptor,
96            crate::filesystem::ErrorCode::Busy => Self::Busy,
97            crate::filesystem::ErrorCode::Exist => Self::Exist,
98            crate::filesystem::ErrorCode::FileTooLarge => Self::FileTooLarge,
99            crate::filesystem::ErrorCode::IllegalByteSequence => Self::IllegalByteSequence,
100            crate::filesystem::ErrorCode::InProgress => Self::InProgress,
101            crate::filesystem::ErrorCode::Interrupted => Self::Interrupted,
102            crate::filesystem::ErrorCode::Invalid => Self::Invalid,
103            crate::filesystem::ErrorCode::Io => Self::Io,
104            crate::filesystem::ErrorCode::IsDirectory => Self::IsDirectory,
105            crate::filesystem::ErrorCode::Loop => Self::Loop,
106            crate::filesystem::ErrorCode::TooManyLinks => Self::TooManyLinks,
107            crate::filesystem::ErrorCode::NameTooLong => Self::NameTooLong,
108            crate::filesystem::ErrorCode::NoEntry => Self::NoEntry,
109            crate::filesystem::ErrorCode::InsufficientMemory => Self::InsufficientMemory,
110            crate::filesystem::ErrorCode::InsufficientSpace => Self::InsufficientSpace,
111            crate::filesystem::ErrorCode::NotDirectory => Self::NotDirectory,
112            crate::filesystem::ErrorCode::NotEmpty => Self::NotEmpty,
113            crate::filesystem::ErrorCode::Unsupported => Self::Unsupported,
114            crate::filesystem::ErrorCode::Overflow => Self::Overflow,
115            crate::filesystem::ErrorCode::NotPermitted => Self::NotPermitted,
116            crate::filesystem::ErrorCode::Pipe => Self::Pipe,
117            crate::filesystem::ErrorCode::InvalidSeek => Self::InvalidSeek,
118        }
119    }
120}
121
122impl From<crate::filesystem::ErrorCode> for FilesystemError {
123    fn from(error: crate::filesystem::ErrorCode) -> Self {
124        types::ErrorCode::from(error).into()
125    }
126}
127
128impl From<wasmtime::component::ResourceTableError> for FilesystemError {
129    fn from(error: wasmtime::component::ResourceTableError) -> Self {
130        Self::trap(error)
131    }
132}
133
134impl From<types::Advice> for system_interface::fs::Advice {
135    fn from(advice: types::Advice) -> Self {
136        match advice {
137            types::Advice::Normal => Self::Normal,
138            types::Advice::Sequential => Self::Sequential,
139            types::Advice::Random => Self::Random,
140            types::Advice::WillNeed => Self::WillNeed,
141            types::Advice::DontNeed => Self::DontNeed,
142            types::Advice::NoReuse => Self::NoReuse,
143        }
144    }
145}
146
147impl From<types::OpenFlags> for crate::filesystem::OpenFlags {
148    fn from(flags: types::OpenFlags) -> Self {
149        let mut out = Self::empty();
150        if flags.contains(types::OpenFlags::CREATE) {
151            out |= Self::CREATE;
152        }
153        if flags.contains(types::OpenFlags::DIRECTORY) {
154            out |= Self::DIRECTORY;
155        }
156        if flags.contains(types::OpenFlags::EXCLUSIVE) {
157            out |= Self::EXCLUSIVE;
158        }
159        if flags.contains(types::OpenFlags::TRUNCATE) {
160            out |= Self::TRUNCATE;
161        }
162        out
163    }
164}
165
166impl From<types::PathFlags> for crate::filesystem::PathFlags {
167    fn from(flags: types::PathFlags) -> Self {
168        let mut out = Self::empty();
169        if flags.contains(types::PathFlags::SYMLINK_FOLLOW) {
170            out |= Self::SYMLINK_FOLLOW;
171        }
172        out
173    }
174}
175
176impl From<crate::filesystem::DescriptorFlags> for types::DescriptorFlags {
177    fn from(flags: crate::filesystem::DescriptorFlags) -> Self {
178        let mut out = Self::empty();
179        if flags.contains(crate::filesystem::DescriptorFlags::READ) {
180            out |= Self::READ;
181        }
182        if flags.contains(crate::filesystem::DescriptorFlags::WRITE) {
183            out |= Self::WRITE;
184        }
185        if flags.contains(crate::filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) {
186            out |= Self::FILE_INTEGRITY_SYNC;
187        }
188        if flags.contains(crate::filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) {
189            out |= Self::DATA_INTEGRITY_SYNC;
190        }
191        if flags.contains(crate::filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) {
192            out |= Self::REQUESTED_WRITE_SYNC;
193        }
194        if flags.contains(crate::filesystem::DescriptorFlags::MUTATE_DIRECTORY) {
195            out |= Self::MUTATE_DIRECTORY;
196        }
197        out
198    }
199}
200
201impl From<types::DescriptorFlags> for crate::filesystem::DescriptorFlags {
202    fn from(flags: types::DescriptorFlags) -> Self {
203        let mut out = Self::empty();
204        if flags.contains(types::DescriptorFlags::READ) {
205            out |= Self::READ;
206        }
207        if flags.contains(types::DescriptorFlags::WRITE) {
208            out |= Self::WRITE;
209        }
210        if flags.contains(types::DescriptorFlags::FILE_INTEGRITY_SYNC) {
211            out |= Self::FILE_INTEGRITY_SYNC;
212        }
213        if flags.contains(types::DescriptorFlags::DATA_INTEGRITY_SYNC) {
214            out |= Self::DATA_INTEGRITY_SYNC;
215        }
216        if flags.contains(types::DescriptorFlags::REQUESTED_WRITE_SYNC) {
217            out |= Self::REQUESTED_WRITE_SYNC;
218        }
219        if flags.contains(types::DescriptorFlags::MUTATE_DIRECTORY) {
220            out |= Self::MUTATE_DIRECTORY;
221        }
222        out
223    }
224}
225
226impl From<crate::filesystem::MetadataHashValue> for types::MetadataHashValue {
227    fn from(
228        crate::filesystem::MetadataHashValue { lower, upper }: crate::filesystem::MetadataHashValue,
229    ) -> Self {
230        Self { lower, upper }
231    }
232}
233
234impl From<crate::filesystem::DescriptorStat> for types::DescriptorStat {
235    fn from(
236        crate::filesystem::DescriptorStat {
237            type_,
238            link_count,
239            size,
240            data_access_timestamp,
241            data_modification_timestamp,
242            status_change_timestamp,
243        }: crate::filesystem::DescriptorStat,
244    ) -> Self {
245        Self {
246            type_: type_.into(),
247            link_count,
248            size,
249            data_access_timestamp: data_access_timestamp.map(Into::into),
250            data_modification_timestamp: data_modification_timestamp.map(Into::into),
251            status_change_timestamp: status_change_timestamp.map(Into::into),
252        }
253    }
254}
255
256impl From<crate::filesystem::DescriptorType> for types::DescriptorType {
257    fn from(ty: crate::filesystem::DescriptorType) -> Self {
258        match ty {
259            crate::filesystem::DescriptorType::Unknown => Self::Unknown,
260            crate::filesystem::DescriptorType::BlockDevice => Self::BlockDevice,
261            crate::filesystem::DescriptorType::CharacterDevice => Self::CharacterDevice,
262            crate::filesystem::DescriptorType::Directory => Self::Directory,
263            crate::filesystem::DescriptorType::SymbolicLink => Self::SymbolicLink,
264            crate::filesystem::DescriptorType::RegularFile => Self::RegularFile,
265        }
266    }
267}
268
269impl From<cap_std::fs::FileType> for types::DescriptorType {
270    fn from(ft: cap_std::fs::FileType) -> Self {
271        use cap_fs_ext::FileTypeExt as _;
272        if ft.is_dir() {
273            Self::Directory
274        } else if ft.is_symlink() {
275            Self::SymbolicLink
276        } else if ft.is_block_device() {
277            Self::BlockDevice
278        } else if ft.is_char_device() {
279            Self::CharacterDevice
280        } else if ft.is_file() {
281            Self::RegularFile
282        } else {
283            Self::Unknown
284        }
285    }
286}