Skip to main content

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