async_wasi/snapshots/common/vfs/
impls.rs1use 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}