async_wasi/snapshots/common/vfs/
impls.rs

1use std::{
2    collections::HashMap,
3    fmt::Debug,
4    io::{Read, Seek, Write},
5};
6
7use crate::snapshots::env::Errno;
8
9use super::{
10    virtual_sys::{WasiVirtualDir, WasiVirtualFile},
11    WasiDir, WasiFile, WasiNode,
12};
13
14#[derive(Debug)]
15struct DirEntry {
16    ino: usize,
17    is_dir: bool,
18}
19
20#[derive(Debug)]
21pub struct MemoryDir {
22    ino: usize,
23    nlink: usize,
24    paths: HashMap<String, DirEntry>,
25    is_open: usize,
26}
27
28impl Drop for MemoryDir {
29    fn drop(&mut self) {
30        log::trace!("\r\n{self:#?}")
31    }
32}
33
34impl Drop for MemoryFile {
35    fn drop(&mut self) {
36        log::trace!("\r\n{self:#?} \r\n {:#?}", self.context.get_ref());
37    }
38}
39
40impl WasiNode for MemoryDir {
41    fn fd_fdstat_get(&self) -> Result<super::FdStat, Errno> {
42        Ok(super::FdStat {
43            filetype: super::FileType::DIRECTORY,
44            fs_rights_base: super::WASIRights::dir_all(),
45            fs_rights_inheriting: super::WASIRights::fd_all(),
46            flags: super::FdFlags::empty(),
47        })
48    }
49
50    fn fd_filestat_get(&self) -> Result<super::Filestat, Errno> {
51        Ok(super::Filestat {
52            filetype: super::FileType::DIRECTORY,
53            inode: self.ino as _,
54            nlink: self.nlink as _,
55            size: self.paths.len() as _,
56            atim: None,
57            mtim: None,
58            ctim: None,
59        })
60    }
61
62    fn fd_filestat_set_size(
63        &mut self,
64        size: crate::snapshots::env::wasi_types::__wasi_filesize_t,
65    ) -> Result<(), Errno> {
66        Err(Errno::__WASI_ERRNO_BADF)
67    }
68
69    fn fd_filestat_set_times(
70        &mut self,
71        atim: crate::snapshots::env::wasi_types::__wasi_timestamp_t,
72        mtim: crate::snapshots::env::wasi_types::__wasi_timestamp_t,
73        fst_flags: crate::snapshots::env::wasi_types::__wasi_fstflags_t::Type,
74    ) -> Result<(), Errno> {
75        Ok(())
76    }
77}
78
79impl WasiDir for MemoryDir {
80    fn get_readdir(&self, start: u64) -> Result<Vec<(String, u64, super::FileType)>, Errno> {
81        let mut r = vec![];
82        for (path, DirEntry { ino, is_dir }) in self.paths.iter().skip(start as usize) {
83            r.push((
84                path.clone(),
85                *ino as _,
86                if *is_dir {
87                    super::FileType::DIRECTORY
88                } else {
89                    super::FileType::REGULAR_FILE
90                },
91            ));
92        }
93        Ok(r)
94    }
95}
96
97impl WasiVirtualDir for MemoryDir {
98    fn create(ino: usize) -> Self {
99        let mut paths = HashMap::default();
100        paths.insert(".".to_string(), DirEntry { ino, is_dir: true });
101        if ino == 0 {
102            paths.insert("..".to_string(), DirEntry { ino, is_dir: true });
103        }
104
105        Self {
106            ino,
107            paths,
108            is_open: 0,
109            nlink: 1,
110        }
111    }
112
113    fn add_sub_dir<P: AsRef<std::path::Path>>(
114        &mut self,
115        path: &P,
116        ino: usize,
117    ) -> Result<(), Errno> {
118        self.paths.insert(
119            path.as_ref()
120                .to_str()
121                .ok_or(Errno::__WASI_ERRNO_ILSEQ)?
122                .to_string(),
123            DirEntry { ino, is_dir: true },
124        );
125        self.nlink += 1;
126        Ok(())
127    }
128
129    fn remove_sub_dir<P: AsRef<std::path::Path>>(&mut self, path: &P) -> Result<(), Errno> {
130        let path = path.as_ref().to_str().ok_or(Errno::__WASI_ERRNO_ILSEQ)?;
131        if let Some(DirEntry { ino, is_dir }) = self.paths.remove(path) {
132            if is_dir && self.nlink > 1 {
133                self.nlink -= 1;
134            }
135            Ok(())
136        } else {
137            Err(Errno::__WASI_ERRNO_NOENT)
138        }
139    }
140
141    fn link_inode<P: AsRef<std::path::Path>>(
142        &mut self,
143        path: &P,
144        ino: usize,
145    ) -> Result<(), crate::snapshots::env::Errno> {
146        self.paths.insert(
147            path.as_ref()
148                .to_str()
149                .ok_or(Errno::__WASI_ERRNO_ILSEQ)?
150                .to_string(),
151            DirEntry { ino, is_dir: false },
152        );
153        Ok(())
154    }
155
156    fn unlink_inode<P: AsRef<std::path::Path>>(
157        &mut self,
158        path: &P,
159    ) -> Result<(), crate::snapshots::env::Errno> {
160        let path = path.as_ref().to_str().ok_or(Errno::__WASI_ERRNO_ILSEQ)?;
161        if self.paths.remove(path).is_some() {
162            Ok(())
163        } else {
164            Err(Errno::__WASI_ERRNO_NOENT)
165        }
166    }
167
168    fn find_inode<P: AsRef<std::path::Path>>(&self, path: &P) -> Option<usize> {
169        let path = path.as_ref().to_str()?;
170        if path.is_empty() {
171            return Some(self.ino);
172        }
173        let entry = self.paths.get(path)?;
174        Some(entry.ino)
175    }
176
177    fn is_empty(&self) -> bool {
178        self.paths.len() <= 2
179    }
180
181    fn is_open(&self) -> bool {
182        self.is_open > 0
183    }
184
185    fn open(&mut self) {
186        self.is_open += 1;
187    }
188
189    fn close(&mut self) -> usize {
190        if self.is_open > 0 {
191            self.is_open -= 1;
192        }
193        self.nlink
194    }
195
196    fn mark_remove(&mut self) {
197        self.nlink = 0
198    }
199}
200
201pub struct MemoryFile {
202    context: std::io::Cursor<Vec<u8>>,
203    nlink: usize,
204    ino: usize,
205    is_open: bool,
206}
207
208impl WasiNode for MemoryFile {
209    fn fd_fdstat_get(&self) -> Result<super::FdStat, Errno> {
210        Ok(super::FdStat {
211            filetype: super::FileType::REGULAR_FILE,
212            fs_rights_base: super::WASIRights::dir_all(),
213            fs_rights_inheriting: super::WASIRights::fd_all(),
214            flags: super::FdFlags::empty(),
215        })
216    }
217
218    fn fd_filestat_get(&self) -> Result<super::Filestat, Errno> {
219        Ok(super::Filestat {
220            filetype: super::FileType::REGULAR_FILE,
221            inode: self.ino as _,
222            nlink: self.nlink as _,
223            size: self.context.get_ref().len() as _,
224            atim: None,
225            mtim: None,
226            ctim: None,
227        })
228    }
229
230    fn fd_filestat_set_size(
231        &mut self,
232        size: crate::snapshots::env::wasi_types::__wasi_filesize_t,
233    ) -> Result<(), Errno> {
234        Err(Errno::__WASI_ERRNO_NOTSUP)
235    }
236
237    fn fd_filestat_set_times(
238        &mut self,
239        atim: crate::snapshots::env::wasi_types::__wasi_timestamp_t,
240        mtim: crate::snapshots::env::wasi_types::__wasi_timestamp_t,
241        fst_flags: crate::snapshots::env::wasi_types::__wasi_fstflags_t::Type,
242    ) -> Result<(), Errno> {
243        Ok(())
244    }
245}
246
247impl WasiFile for MemoryFile {
248    fn fd_read(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> Result<usize, Errno> {
249        Ok(self.context.read_vectored(bufs)?)
250    }
251
252    fn fd_pread(
253        &mut self,
254        bufs: &mut [std::io::IoSliceMut<'_>],
255        offset: crate::snapshots::env::wasi_types::__wasi_filesize_t,
256    ) -> Result<usize, Errno> {
257        let old_pos = self.context.position();
258        self.context.set_position(offset);
259        let n = self.context.read_vectored(bufs);
260        self.context.set_position(old_pos);
261        Ok(n?)
262    }
263
264    fn fd_write(&mut self, bufs: &[std::io::IoSlice<'_>]) -> Result<usize, Errno> {
265        Ok(self.context.write_vectored(bufs)?)
266    }
267
268    fn fd_pwrite(
269        &mut self,
270        bufs: &[std::io::IoSlice<'_>],
271        offset: crate::snapshots::env::wasi_types::__wasi_filesize_t,
272    ) -> Result<usize, Errno> {
273        let old_pos = self.context.position();
274        self.context.set_position(offset);
275        let n = self.context.write_vectored(bufs);
276        self.context.set_position(old_pos);
277        Ok(n?)
278    }
279
280    fn fd_seek(
281        &mut self,
282        offset: crate::snapshots::env::wasi_types::__wasi_filedelta_t,
283        whence: crate::snapshots::env::wasi_types::__wasi_whence_t::Type,
284    ) -> Result<crate::snapshots::env::wasi_types::__wasi_filesize_t, Errno> {
285        let pos = match whence {
286            crate::snapshots::env::wasi_types::__wasi_whence_t::__WASI_WHENCE_CUR => {
287                std::io::SeekFrom::Current(offset)
288            }
289            crate::snapshots::env::wasi_types::__wasi_whence_t::__WASI_WHENCE_END => {
290                std::io::SeekFrom::End(offset)
291            }
292            crate::snapshots::env::wasi_types::__wasi_whence_t::__WASI_WHENCE_SET => {
293                std::io::SeekFrom::Start(offset as u64)
294            }
295            _ => return Err(Errno::__WASI_ERRNO_INVAL),
296        };
297        Ok(self.context.seek(pos)?)
298    }
299
300    fn fd_tell(&mut self) -> Result<crate::snapshots::env::wasi_types::__wasi_filesize_t, Errno> {
301        Ok(self.context.position() as _)
302    }
303}
304
305impl From<Vec<u8>> for MemoryFile {
306    fn from(value: Vec<u8>) -> Self {
307        Self {
308            context: std::io::Cursor::new(value),
309            nlink: 0,
310            ino: 0,
311            is_open: false,
312        }
313    }
314}
315
316impl WasiVirtualFile for MemoryFile {
317    fn create(ino: usize) -> Self {
318        Self {
319            context: std::io::Cursor::new(Vec::new()),
320            nlink: 0,
321            ino,
322            is_open: false,
323        }
324    }
325
326    fn set_ino(&mut self, ino: usize) {
327        self.ino = ino;
328    }
329
330    fn inc_link(&mut self) -> Result<usize, Errno> {
331        self.nlink += 1;
332        Ok(self.nlink)
333    }
334
335    fn dec_link(&mut self) -> Result<usize, Errno> {
336        if self.nlink > 0 {
337            self.nlink -= 1;
338        }
339        Ok(self.nlink)
340    }
341
342    fn is_open(&self) -> bool {
343        self.is_open
344    }
345
346    fn open(&mut self) {
347        self.is_open = true;
348    }
349
350    fn close(&mut self) -> usize {
351        self.is_open = false;
352        self.nlink
353    }
354}
355
356impl Debug for MemoryFile {
357    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358        f.debug_struct("MemoryFile")
359            .field("context_len", &self.context.get_ref().len())
360            .field("nlink", &self.nlink)
361            .field("ino", &self.ino)
362            .field("is_open", &self.is_open)
363            .finish()
364    }
365}