1use std::{
2 io::{Read, Seek, Write},
3 path::{Path, PathBuf},
4 time::Duration,
5};
6
7use futures::future::ok;
8use libc::hostent;
9use slab::Slab;
10
11use crate::snapshots::env::{wasi_types, Errno};
12
13use super::{
14 Advice, FdFlags, FdStat, FileType, Filestat, OFlags, SystemTimeSpec, WASIRights, WasiDir,
15 WasiFile, WasiFileSys, WasiNode,
16};
17
18pub trait WasiVirtualDir: WasiDir {
19 fn create(ino: usize) -> Self;
20 fn add_sub_dir<P: AsRef<Path>>(&mut self, path: &P, ino: usize) -> Result<(), Errno>;
21 fn remove_sub_dir<P: AsRef<Path>>(&mut self, path: &P) -> Result<(), Errno>;
22
23 fn link_inode<P: AsRef<Path>>(&mut self, path: &P, ino: usize) -> Result<(), Errno>;
24 fn unlink_inode<P: AsRef<Path>>(&mut self, path: &P) -> Result<(), Errno>;
25 fn find_inode<P: AsRef<Path>>(&self, path: &P) -> Option<usize>;
26 fn is_empty(&self) -> bool;
27
28 fn is_open(&self) -> bool;
29 fn open(&mut self);
30 fn close(&mut self) -> usize;
31 fn mark_remove(&mut self);
32}
33
34pub trait WasiVirtualFile: WasiFile {
35 fn create(ino: usize) -> Self;
36
37 fn set_ino(&mut self, ino: usize);
38
39 fn inc_link(&mut self) -> Result<usize, Errno>;
40
41 fn dec_link(&mut self) -> Result<usize, Errno>;
42
43 fn is_open(&self) -> bool;
44 fn open(&mut self);
45 fn close(&mut self) -> usize;
46}
47
48pub enum Inode<D: WasiVirtualDir, F: WasiVirtualFile> {
49 Dir(D),
50 File(F),
51}
52
53impl<D: WasiVirtualDir, F: WasiVirtualFile> WasiNode for Inode<D, F> {
54 fn fd_fdstat_get(&self) -> Result<FdStat, Errno> {
55 match self {
56 Inode::Dir(dir) => dir.fd_fdstat_get(),
57 Inode::File(file) => file.fd_fdstat_get(),
58 }
59 }
60
61 fn fd_fdstat_set_flags(&mut self, flags: FdFlags) -> Result<(), Errno> {
62 match self {
63 Inode::Dir(dir) => dir.fd_fdstat_set_flags(flags),
64 Inode::File(file) => file.fd_fdstat_set_flags(flags),
65 }
66 }
67
68 fn fd_fdstat_set_rights(
69 &mut self,
70 fs_rights_base: WASIRights,
71 fs_rights_inheriting: WASIRights,
72 ) -> Result<(), Errno> {
73 match self {
74 Inode::Dir(dir) => dir.fd_fdstat_set_rights(fs_rights_base, fs_rights_inheriting),
75 Inode::File(file) => file.fd_fdstat_set_rights(fs_rights_base, fs_rights_inheriting),
76 }
77 }
78
79 fn fd_filestat_get(&self) -> Result<Filestat, Errno> {
80 match self {
81 Inode::Dir(dir) => dir.fd_filestat_get(),
82 Inode::File(file) => file.fd_filestat_get(),
83 }
84 }
85
86 fn fd_filestat_set_size(&mut self, size: wasi_types::__wasi_filesize_t) -> Result<(), Errno> {
87 match self {
88 Inode::Dir(dir) => dir.fd_filestat_set_size(size),
89 Inode::File(file) => file.fd_filestat_set_size(size),
90 }
91 }
92
93 fn fd_filestat_set_times(
94 &mut self,
95 atim: wasi_types::__wasi_timestamp_t,
96 mtim: wasi_types::__wasi_timestamp_t,
97 fst_flags: wasi_types::__wasi_fstflags_t::Type,
98 ) -> Result<(), Errno> {
99 match self {
100 Inode::Dir(dir) => dir.fd_filestat_set_times(atim, mtim, fst_flags),
101 Inode::File(file) => file.fd_filestat_set_times(atim, mtim, fst_flags),
102 }
103 }
104}
105
106pub struct WasiVirtualSys<D: WasiVirtualDir, F: WasiVirtualFile> {
108 inodes: slab::Slab<Inode<D, F>>,
109 dir_rights: WASIRights,
110 file_rights: WASIRights,
111}
112
113impl<D: WasiVirtualDir, F: WasiVirtualFile> Default for WasiVirtualSys<D, F> {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119impl<D: WasiVirtualDir, F: WasiVirtualFile> WasiVirtualSys<D, F> {
120 pub fn new() -> Self {
121 let mut inodes = Slab::new();
122 inodes.insert(Inode::Dir(D::create(0)));
123 Self {
124 inodes,
125 dir_rights: WASIRights::dir_all(),
126 file_rights: WASIRights::fd_all(),
127 }
128 }
129
130 pub fn create_file<P: AsRef<Path>>(
131 &mut self,
132 dir_ino: usize,
133 path: &P,
134 mut new_file: F,
135 ) -> Result<usize, Errno> {
136 new_file.inc_link();
137 let new_ino = self.inodes.vacant_key();
138 new_file.set_ino(new_ino);
139 let new_ino = self.inodes.insert(Inode::File(new_file));
140
141 if let Some(Inode::Dir(dir)) = self.inodes.get_mut(dir_ino) {
142 let r = dir.link_inode(path, new_ino);
143 if r.is_err() {
144 self.inodes.remove(new_ino);
145 }
146 r?;
147 Ok(new_ino)
148 } else {
149 self.inodes.remove(new_ino);
150 Err(Errno::__WASI_ERRNO_NOTDIR)
151 }
152 }
153
154 pub fn find_inode_index<P: AsRef<Path>>(
155 &self,
156 dir_ino: usize,
157 path: &P,
158 ) -> Result<usize, Errno> {
159 let mut ino = dir_ino;
160 let path = path.as_ref();
161 let path_iter = path.iter();
162 for entry in path.iter() {
163 let entry = entry.to_str().ok_or(Errno::__WASI_ERRNO_ILSEQ)?;
164 log::trace!("WasiVirtualSys find_inode_index {ino} {entry}");
165
166 if let Inode::Dir(dir) = self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_NOENT)? {
167 ino = dir.find_inode(&entry).ok_or(Errno::__WASI_ERRNO_NOENT)?;
168 } else {
169 return Err(Errno::__WASI_ERRNO_NOTDIR);
170 }
171 }
172 log::trace!("WasiVirtualSys find_inode_index return {ino}");
173 Ok(ino)
174 }
175
176 pub fn create_file_inode<P: AsRef<Path>>(
177 &mut self,
178 dir_ino: usize,
179 path: &P,
180 ) -> Result<usize, Errno> {
181 let mut new_file = F::create(self.inodes.vacant_key());
182 new_file.inc_link();
183 let new_ino = self.inodes.insert(Inode::File(new_file));
184
185 if let Some(Inode::Dir(dir)) = self.inodes.get_mut(dir_ino) {
186 let r = dir.link_inode(path, new_ino);
187 if r.is_err() {
188 self.inodes.remove(new_ino);
189 }
190 r?;
191 Ok(new_ino)
192 } else {
193 self.inodes.remove(new_ino);
194 Err(Errno::__WASI_ERRNO_NOTDIR)
195 }
196 }
197
198 pub fn create_dir_inode<P: AsRef<Path>>(
199 &mut self,
200 dir_ino: usize,
201 path: &P,
202 ) -> Result<usize, Errno> {
203 let mut new_dir = D::create(self.inodes.vacant_key());
204 new_dir.add_sub_dir(&"..", dir_ino);
205 let new_ino = self.inodes.insert(Inode::Dir(new_dir));
206
207 if let Some(Inode::Dir(dir)) = self.inodes.get_mut(dir_ino) {
208 let r = dir.add_sub_dir(path, new_ino);
209 if r.is_err() {
210 self.inodes.remove(new_ino);
211 }
212 r?;
213 Ok(new_ino)
214 } else {
215 self.inodes.remove(new_ino);
216 Err(Errno::__WASI_ERRNO_NOTDIR)
217 }
218 }
219}
220
221impl<D: WasiVirtualDir, F: WasiVirtualFile> WasiFileSys for WasiVirtualSys<D, F> {
222 type Index = usize;
223
224 fn path_open(
225 &mut self,
226 dir_ino: Self::Index,
227 path: &str,
228 oflags: OFlags,
229 fs_rights_base: WASIRights,
230 fs_rights_inheriting: WASIRights,
231 fdflags: FdFlags,
232 ) -> Result<usize, Errno> {
233 let path: &Path = path.as_ref();
234
235 log::trace!("WasiVirtualSys path_open {oflags:?} {path:?} {dir_ino}");
236
237 if fdflags.intersects(FdFlags::DSYNC | FdFlags::SYNC | FdFlags::RSYNC) {
238 return Err(Errno::__WASI_ERRNO_NOSYS);
239 }
240
241 if oflags.intersects(OFlags::DIRECTORY)
242 && (oflags.contains(OFlags::CREATE)
243 || oflags.contains(OFlags::EXCLUSIVE)
244 || oflags.contains(OFlags::TRUNCATE))
245 {
246 return Err(Errno::__WASI_ERRNO_INVAL);
247 }
248
249 let read = fs_rights_base.contains(WASIRights::FD_READ);
250 let write = fs_rights_base.contains(WASIRights::FD_WRITE);
251
252 let inode = self.find_inode_index(dir_ino, &path);
253 match inode {
254 Ok(ino) => match self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_NOENT)? {
255 Inode::Dir(dir) => {
256 dir.open();
257 Ok(ino)
258 }
259 Inode::File(file) => {
260 if oflags.intersects(OFlags::DIRECTORY) {
261 return Err(Errno::__WASI_ERRNO_NOTDIR);
262 }
263
264 if oflags.intersects(OFlags::CREATE | OFlags::EXCLUSIVE) {
265 return Err(Errno::__WASI_ERRNO_EXIST);
266 }
267
268 file.open();
269
270 Ok(ino)
271 }
272 },
273 Err(e) => {
274 if oflags.intersects(OFlags::DIRECTORY) {
275 return Err(e);
276 }
277
278 if oflags.intersects(OFlags::CREATE) {
279 let parent = match path.parent() {
280 Some(p) => self.find_inode_index(dir_ino, &p)?,
281 None => dir_ino,
282 };
283
284 let ino = self.create_file_inode(
285 parent,
286 &path.file_name().ok_or(Errno::__WASI_ERRNO_INVAL)?,
287 )?;
288 if let Some(Inode::File(file)) = self.inodes.get_mut(ino) {
289 file.open();
290 }
291
292 return Ok(ino);
293 }
294
295 Err(Errno::__WASI_ERRNO_EXIST)
296 }
297 }
298 }
299
300 fn path_rename(
301 &mut self,
302 old_dir: usize,
303 old_path: &str,
304 new_dir: usize,
305 new_path: &str,
306 ) -> Result<(), Errno> {
307 self.path_link_file(old_dir, old_path, new_dir, new_path)?;
308 self.path_unlink_file(old_dir, old_path)?;
309 Ok(())
310 }
311
312 fn path_create_directory(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
313 let path: &Path = path.as_ref();
314 self.dir_rights.can(WASIRights::PATH_CREATE_DIRECTORY)?;
315
316 let mut ino = dir_ino;
317 let path_iter = path.iter();
318 for entry in path.iter() {
319 let entry = entry.to_str().ok_or(Errno::__WASI_ERRNO_ILSEQ)?;
320
321 match self.inodes.get(ino) {
322 Some(Inode::Dir(dir)) => {
323 if let Some(sub_ino) = dir.find_inode(&entry) {
324 ino = sub_ino;
325 } else {
326 ino = self.create_dir_inode(ino, &entry)?;
327 }
328 }
329 Some(Inode::File(_)) => {
330 return Err(Errno::__WASI_ERRNO_NOTDIR);
331 }
332 None => {
333 return Err(Errno::__WASI_ERRNO_NOENT);
334 }
335 }
336 }
337 Ok(())
338 }
339
340 fn fclose(&mut self, ino: Self::Index) -> Result<(), Errno> {
341 let i = match self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
342 Inode::Dir(dir) => dir.close(),
343 Inode::File(file) => file.close(),
344 };
345 log::trace!("WasiVirtualSys path_open {ino} close_r={i}");
346 if i == 0 {
347 self.inodes.remove(ino);
348 }
349 Ok(())
350 }
351
352 fn path_remove_directory(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
353 self.dir_rights.can(WASIRights::PATH_REMOVE_DIRECTORY)?;
354 let inode = self.find_inode_index(dir_ino, &path)?;
355 if let (Inode::Dir(dir), Inode::Dir(parent_dir)) = self
356 .inodes
357 .get2_mut(inode, dir_ino)
358 .ok_or(Errno::__WASI_ERRNO_NOENT)?
359 {
360 if dir.is_empty() {
361 parent_dir.remove_sub_dir(&path)?;
362
363 if !dir.is_open() {
364 self.inodes.remove(inode);
365 } else {
366 dir.mark_remove();
367 }
368
369 Ok(())
370 } else {
371 Err(Errno::__WASI_ERRNO_NOTEMPTY)
372 }
373 } else {
374 Err(Errno::__WASI_ERRNO_NOTDIR)
375 }
376 }
377
378 fn path_unlink_file(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
379 log::trace!("WasiVirtualSys path_unlink_file {dir_ino} {path}");
380 self.dir_rights.can(WASIRights::PATH_UNLINK_FILE)?;
381
382 let path: &Path = path.as_ref();
383 let parent_dir_ino = if let Some(parent) = path.parent() {
384 self.find_inode_index(dir_ino, &parent)?
385 } else {
386 dir_ino
387 };
388
389 let file_name = path
390 .file_name()
391 .ok_or(Errno::__WASI_ERRNO_INVAL)?
392 .to_str()
393 .ok_or(Errno::__WASI_ERRNO_ILSEQ)?;
394
395 let file_ino = if let Inode::Dir(dir) = self
396 .inodes
397 .get_mut(parent_dir_ino)
398 .ok_or(Errno::__WASI_ERRNO_BADF)?
399 {
400 let file_ino = dir
401 .find_inode(&file_name)
402 .ok_or(Errno::__WASI_ERRNO_NOENT)?;
403 dir.unlink_inode(&file_name)?;
404 file_ino
405 } else {
406 return Err(Errno::__WASI_ERRNO_NOTDIR);
407 };
408
409 if let Inode::File(file) = self
410 .inodes
411 .get_mut(file_ino)
412 .ok_or(Errno::__WASI_ERRNO_BADF)?
413 {
414 let link = file.dec_link()?;
415 log::trace!("WasiVirtualSys path_unlink_file {file_ino} nlink = {link}");
416
417 if link == 0 && !file.is_open() {
418 self.inodes.try_remove(file_ino);
419 }
420 Ok(())
421 } else {
422 Err(Errno::__WASI_ERRNO_ISDIR)
423 }
424 }
425
426 fn path_link_file(
427 &mut self,
428 old_dir: usize,
429 old_path: &str,
430 new_dir: usize,
431 new_path: &str,
432 ) -> Result<(), Errno> {
433 log::trace!("WasiVirtualSys path_link_file ({old_dir} {old_path}) ({new_dir} {new_path})");
434
435 let old_inode = self.find_inode_index(old_dir, &old_path)?;
436
437 let new_path: &Path = new_path.as_ref();
438 let parent_dir_ino = if let Some(parent) = new_path.parent() {
439 self.find_inode_index(new_dir, &parent)?
440 } else {
441 new_dir
442 };
443
444 let file_name = new_path
445 .file_name()
446 .ok_or(Errno::__WASI_ERRNO_INVAL)?
447 .to_str()
448 .ok_or(Errno::__WASI_ERRNO_ILSEQ)?;
449
450 if let Inode::Dir(dir) = self
451 .inodes
452 .get_mut(parent_dir_ino)
453 .ok_or(Errno::__WASI_ERRNO_BADF)?
454 {
455 dir.link_inode(&file_name, old_inode)?;
456 } else {
457 return Err(Errno::__WASI_ERRNO_NOTDIR);
458 };
459
460 if let Inode::File(file) = self
461 .inodes
462 .get_mut(old_inode)
463 .ok_or(Errno::__WASI_ERRNO_BADF)?
464 {
465 let nlink = file.inc_link()?;
466 log::trace!("WasiVirtualSys path_link_file {old_inode} nlink = {nlink}");
467 } else {
468 return Err(Errno::__WASI_ERRNO_ISDIR);
469 };
470
471 Ok(())
472 }
473
474 fn path_filestat_get(
475 &self,
476 dir_ino: Self::Index,
477 path: &str,
478 follow_symlinks: bool,
479 ) -> Result<Filestat, Errno> {
480 let path: &Path = path.as_ref();
481
482 self.dir_rights.can(WASIRights::PATH_FILESTAT_GET)?;
483 let inode = self.find_inode_index(dir_ino, &path)?;
484 self.inodes
485 .get(inode)
486 .ok_or(Errno::__WASI_ERRNO_NOENT)?
487 .fd_filestat_get()
488 }
489
490 fn get_mut_inode(&mut self, ino: usize) -> Result<&mut dyn WasiNode, Errno> {
491 Ok(self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)?)
492 }
493
494 fn get_inode(&self, ino: usize) -> Result<&dyn WasiNode, Errno> {
495 Ok(self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_BADF)?)
496 }
497
498 fn get_mut_file(&mut self, ino: usize) -> Result<&mut dyn WasiFile, Errno> {
499 if let Inode::File(f) = self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
500 Ok(f)
501 } else {
502 Err(Errno::__WASI_ERRNO_ISDIR)
503 }
504 }
505
506 fn get_file(&self, ino: usize) -> Result<&dyn WasiFile, Errno> {
507 if let Inode::File(f) = self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
508 Ok(f)
509 } else {
510 Err(Errno::__WASI_ERRNO_ISDIR)
511 }
512 }
513
514 fn get_mut_dir(&mut self, ino: usize) -> Result<&mut dyn WasiDir, Errno> {
515 if let Inode::Dir(dir) = self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
516 Ok(dir)
517 } else {
518 Err(Errno::__WASI_ERRNO_NOTDIR)
519 }
520 }
521
522 fn get_dir(&self, ino: usize) -> Result<&dyn WasiDir, Errno> {
523 if let Inode::Dir(dir) = self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
524 Ok(dir)
525 } else {
526 Err(Errno::__WASI_ERRNO_NOTDIR)
527 }
528 }
529}
530
531fn get_file_ino(metadata: &std::fs::Metadata) -> u64 {
534 #[cfg(unix)]
535 {
536 use std::os::unix::prelude::MetadataExt;
537 metadata.ino()
538 }
539 #[cfg(not(unix))]
540 {
541 0
542 }
543}
544
545fn get_file_nlink(metadata: &std::fs::Metadata) -> u64 {
546 #[cfg(unix)]
547 {
548 use std::os::unix::prelude::MetadataExt;
549 metadata.nlink()
550 }
551 #[cfg(not(unix))]
552 {
553 1
554 }
555}
556
557fn systimespec(
558 set: bool,
559 ts: wasi_types::__wasi_timestamp_t,
560 now: bool,
561) -> Result<Option<SystemTimeSpec>, Errno> {
562 if set && now {
563 Err(Errno::__WASI_ERRNO_INVAL)
564 } else if set {
565 Ok(Some(SystemTimeSpec::Absolute(Duration::from_nanos(ts))))
566 } else if now {
567 Ok(Some(SystemTimeSpec::SymbolicNow))
568 } else {
569 Ok(None)
570 }
571}
572
573#[derive(Debug)]
574pub struct DiskDir {
575 pub real_path: PathBuf,
577 pub dir_rights: WASIRights,
578 pub file_rights: WASIRights,
579}
580
581impl DiskDir {
582 pub fn get_absolutize_path<P: AsRef<Path>>(&self, sub_path: &P) -> Result<PathBuf, Errno> {
583 use path_absolutize::*;
584 let new_path = self.real_path.join(sub_path);
585 let absolutize = new_path
586 .absolutize_virtually(&self.real_path)
587 .or(Err(Errno::__WASI_ERRNO_NOENT))?;
588 Ok(absolutize.to_path_buf())
589 }
590}
591
592impl WasiNode for DiskDir {
593 fn fd_fdstat_get(&self) -> Result<FdStat, Errno> {
594 Ok(FdStat {
595 filetype: FileType::DIRECTORY,
596 fs_rights_base: self.dir_rights.clone(),
597 fs_rights_inheriting: self.file_rights.clone(),
598 flags: FdFlags::empty(),
599 })
600 }
601
602 fn fd_fdstat_set_flags(&mut self, flags: FdFlags) -> Result<(), Errno> {
603 Err(Errno::__WASI_ERRNO_BADF)
604 }
605
606 fn fd_fdstat_set_rights(
607 &mut self,
608 fs_rights_base: WASIRights,
609 fs_rights_inheriting: WASIRights,
610 ) -> Result<(), Errno> {
611 self.dir_rights.can(fs_rights_base.clone())?;
612 self.file_rights.can(fs_rights_inheriting.clone())?;
613
614 self.dir_rights = fs_rights_base;
615 self.file_rights = fs_rights_inheriting;
616
617 Ok(())
618 }
619
620 fn fd_filestat_get(&self) -> Result<Filestat, Errno> {
621 self.dir_rights.can(WASIRights::FD_FILESTAT_GET)?;
622 let meta = std::fs::metadata(&self.real_path)?;
623 let filetype = if meta.is_symlink() {
624 FileType::SYMBOLIC_LINK
625 } else {
626 FileType::DIRECTORY
627 };
628
629 let nlink = get_file_nlink(&meta);
630 let inode = get_file_ino(&meta);
631
632 Ok(Filestat {
633 filetype,
634 nlink,
635 inode,
636 size: meta.len(),
637 atim: meta.accessed().ok(),
638 mtim: meta.modified().ok(),
639 ctim: meta.created().ok(),
640 })
641 }
642
643 fn fd_filestat_set_size(&mut self, size: wasi_types::__wasi_filesize_t) -> Result<(), Errno> {
644 Err(Errno::__WASI_ERRNO_BADF)
645 }
646
647 fn fd_filestat_set_times(
648 &mut self,
649 atim: wasi_types::__wasi_timestamp_t,
650 mtim: wasi_types::__wasi_timestamp_t,
651 fst_flags: wasi_types::__wasi_fstflags_t::Type,
652 ) -> Result<(), Errno> {
653 use wasi_types::__wasi_fstflags_t;
654 self.dir_rights.can(WASIRights::FD_FILESTAT_SET_TIMES)?;
655 Err(Errno::__WASI_ERRNO_NOSYS)
656 }
657}
658
659impl WasiDir for DiskDir {
660 fn get_readdir(&self, mut index: u64) -> Result<Vec<(String, u64, FileType)>, Errno> {
661 self.dir_rights.can(WASIRights::FD_READDIR)?;
662
663 let mut dirs = vec![];
664 if index == 0 {
665 let dir_meta = std::fs::metadata(&self.real_path)?;
666 let dir_ino = get_file_ino(&dir_meta);
667 dirs.push((".".to_string(), dir_ino, FileType::DIRECTORY));
668 index += 1;
669 }
670
671 if index == 1 {
672 let dir_ino = if let Some(parent) = self.real_path.parent() {
673 let dir_meta = std::fs::metadata(parent)?;
674 get_file_ino(&dir_meta)
675 } else {
676 0
677 };
678 dirs.push(("..".to_string(), dir_ino, FileType::DIRECTORY));
679 index += 1;
680 }
681
682 let read_dir = self.real_path.read_dir()?;
683
684 for dir_entity in read_dir.into_iter().skip((index - 2) as usize) {
685 let dir_entity = dir_entity?;
686 let name = dir_entity
687 .file_name()
688 .into_string()
689 .map_err(|_| Errno::__WASI_ERRNO_ILSEQ)?;
690 let metadata = dir_entity.metadata()?;
691 let inode = get_file_ino(&metadata);
692
693 let filetype = if metadata.is_dir() {
694 FileType::DIRECTORY
695 } else if metadata.is_symlink() {
696 FileType::SYMBOLIC_LINK
697 } else {
698 FileType::REGULAR_FILE
699 };
700
701 dirs.push((name, inode, filetype));
702 }
703
704 Ok(dirs)
705 }
706}
707
708#[derive(Debug)]
709pub struct DiskFile {
710 pub fd: std::fs::File,
711 pub flags: FdFlags,
712 pub right: WASIRights,
713}
714
715impl WasiNode for DiskFile {
716 fn fd_fdstat_get(&self) -> Result<FdStat, Errno> {
717 let meta = self.fd.metadata()?;
718 let fd_flags = FdStat {
719 filetype: if meta.is_symlink() {
720 FileType::SYMBOLIC_LINK
721 } else {
722 FileType::REGULAR_FILE
723 },
724 fs_rights_base: self.right.clone(),
725 fs_rights_inheriting: WASIRights::empty(),
726 flags: self.flags.clone(),
727 };
728 Ok(fd_flags)
729 }
730
731 fn fd_fdstat_set_flags(&mut self, flags: FdFlags) -> Result<(), Errno> {
732 self.right.can(WASIRights::FD_FDSTAT_SET_FLAGS)?;
733 if flags.contains(FdFlags::NONBLOCK)
734 && flags.intersects(FdFlags::DSYNC | FdFlags::SYNC | FdFlags::RSYNC)
735 {
736 return Err(Errno::__WASI_ERRNO_INVAL);
737 }
738 if flags.contains(FdFlags::APPEND) {
739 return Err(Errno::__WASI_ERRNO_NOSYS);
740 }
741 self.flags = flags;
742 Ok(())
743 }
744
745 fn fd_fdstat_set_rights(
746 &mut self,
747 fs_rights_base: WASIRights,
748 _fs_rights_inheriting: WASIRights,
749 ) -> Result<(), Errno> {
750 self.right.can(fs_rights_base.clone())?;
751 self.right = fs_rights_base;
752 Ok(())
753 }
754
755 fn fd_filestat_get(&self) -> Result<Filestat, Errno> {
756 self.right.can(WASIRights::FD_FILESTAT_GET)?;
757 let meta = self.fd.metadata()?;
758 let filetype = if meta.is_symlink() {
759 FileType::SYMBOLIC_LINK
760 } else {
761 FileType::REGULAR_FILE
762 };
763
764 let nlink = get_file_nlink(&meta);
765 let inode = get_file_ino(&meta);
766
767 Ok(Filestat {
768 filetype,
769 nlink,
770 inode,
771 size: meta.len(),
772 atim: meta.accessed().ok(),
773 mtim: meta.modified().ok(),
774 ctim: meta.created().ok(),
775 })
776 }
777
778 fn fd_filestat_set_size(&mut self, size: wasi_types::__wasi_filesize_t) -> Result<(), Errno> {
779 self.right.can(WASIRights::FD_FILESTAT_SET_SIZE)?;
780 self.fd.set_len(size)?;
781 Ok(())
782 }
783
784 fn fd_filestat_set_times(
785 &mut self,
786 atim: wasi_types::__wasi_timestamp_t,
787 mtim: wasi_types::__wasi_timestamp_t,
788 fst_flags: wasi_types::__wasi_fstflags_t::Type,
789 ) -> Result<(), Errno> {
790 use wasi_types::__wasi_fstflags_t;
791
792 self.right.can(WASIRights::FD_FILESTAT_SET_TIMES)?;
793
794 let set_atim = (fst_flags & __wasi_fstflags_t::__WASI_FSTFLAGS_ATIM) > 0;
795 let set_atim_now = (fst_flags & __wasi_fstflags_t::__WASI_FSTFLAGS_ATIM_NOW) > 0;
796 let set_mtim = (fst_flags & __wasi_fstflags_t::__WASI_FSTFLAGS_MTIM) > 0;
797 let set_mtim_now = (fst_flags & __wasi_fstflags_t::__WASI_FSTFLAGS_MTIM_NOW) > 0;
798
799 let atim = systimespec(set_atim, atim, set_atim_now)?;
800 let mtim = systimespec(set_mtim, mtim, set_mtim_now)?;
801
802 #[cfg(unix)]
803 {
804 use std::os::unix::prelude::AsRawFd;
805 let fd = self.fd.as_raw_fd();
806 let times = [
807 {
808 match atim {
809 Some(SystemTimeSpec::Absolute(atim)) => libc::timespec {
810 tv_sec: atim.as_secs() as i64,
811 tv_nsec: atim.subsec_nanos() as i64,
812 },
813 Some(SystemTimeSpec::SymbolicNow) => libc::timespec {
814 tv_sec: 0,
815 tv_nsec: libc::UTIME_NOW,
816 },
817 None => libc::timespec {
818 tv_sec: 0,
819 tv_nsec: libc::UTIME_OMIT,
820 },
821 }
822 },
823 {
824 match mtim {
825 Some(SystemTimeSpec::Absolute(mtim)) => libc::timespec {
826 tv_sec: mtim.as_secs() as i64,
827 tv_nsec: mtim.subsec_nanos() as i64,
828 },
829 Some(SystemTimeSpec::SymbolicNow) => libc::timespec {
830 tv_sec: 0,
831 tv_nsec: libc::UTIME_NOW,
832 },
833 None => libc::timespec {
834 tv_sec: 0,
835 tv_nsec: libc::UTIME_OMIT,
836 },
837 }
838 },
839 ];
840 if unsafe { libc::futimens(fd, times.as_ptr()) } < 0 {
841 Err(std::io::Error::last_os_error())?;
842 }
843 Ok(())
844 }
845 #[cfg(not(unix))]
846 {
847 Err(Errno::__WASI_ERRNO_NOSYS)
848 }
849 }
850}
851
852impl WasiFile for DiskFile {
853 fn fd_advise(
854 &mut self,
855 offset: wasi_types::__wasi_filesize_t,
856 len: wasi_types::__wasi_filesize_t,
857 advice: Advice,
858 ) -> Result<(), Errno> {
859 Ok(())
860 }
861
862 fn fd_allocate(
863 &mut self,
864 offset: wasi_types::__wasi_filesize_t,
865 len: wasi_types::__wasi_filesize_t,
866 ) -> Result<(), Errno> {
867 self.right.can(WASIRights::FD_ALLOCATE)?;
868 let f = &mut self.fd;
869 let metadata = f.metadata()?;
870 let file_len = metadata.len();
871 let new_len = offset + len;
872 if new_len > file_len {
873 let old_seek = f.stream_position()?;
874 f.set_len(new_len)?;
875 f.seek(std::io::SeekFrom::Start(old_seek))?;
876 }
877 Ok(())
878 }
879
880 fn fd_datasync(&mut self) -> Result<(), Errno> {
881 self.right.can(WASIRights::FD_DATASYNC)?;
882 self.fd.sync_data()?;
883 Ok(())
884 }
885
886 fn fd_sync(&mut self) -> Result<(), Errno> {
887 self.right.can(WASIRights::FD_SYNC)?;
888 self.fd.sync_all()?;
889 Ok(())
890 }
891
892 fn fd_read(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> Result<usize, Errno> {
893 self.right.can(WASIRights::FD_READ)?;
894 Ok(self.fd.read_vectored(bufs)?)
895 }
896
897 fn fd_pread(
898 &mut self,
899 bufs: &mut [std::io::IoSliceMut<'_>],
900 offset: wasi_types::__wasi_filesize_t,
901 ) -> Result<usize, Errno> {
902 use std::io::SeekFrom;
903
904 self.right.can(WASIRights::FD_READ | WASIRights::FD_SEEK)?;
905
906 let old_seek = self.fd.stream_position()?;
907 self.fd.seek(SeekFrom::Start(offset))?;
908 let r = self.fd.read_vectored(bufs);
909 self.fd.seek(SeekFrom::Start(old_seek))?;
910 Ok(r?)
911 }
912
913 fn fd_write(&mut self, bufs: &[std::io::IoSlice<'_>]) -> Result<usize, Errno> {
914 self.right.can(WASIRights::FD_WRITE)?;
915 Ok(self.fd.write_vectored(bufs)?)
916 }
917
918 fn fd_pwrite(
919 &mut self,
920 bufs: &[std::io::IoSlice<'_>],
921 offset: wasi_types::__wasi_filesize_t,
922 ) -> Result<usize, Errno> {
923 use std::io::SeekFrom;
924
925 self.right.can(WASIRights::FD_WRITE | WASIRights::FD_SEEK)?;
926
927 let old_seek = self.fd.stream_position()?;
928 self.fd.seek(SeekFrom::Start(offset))?;
929 let r = self.fd.write_vectored(bufs);
930 self.fd.seek(SeekFrom::Start(old_seek))?;
931 Ok(r?)
932 }
933
934 fn fd_seek(
935 &mut self,
936 offset: wasi_types::__wasi_filedelta_t,
937 whence: wasi_types::__wasi_whence_t::Type,
938 ) -> Result<wasi_types::__wasi_filesize_t, Errno> {
939 use std::io::SeekFrom;
940
941 let required_rigth =
942 if offset == 0 && whence == wasi_types::__wasi_whence_t::__WASI_WHENCE_CUR {
943 WASIRights::FD_TELL
944 } else {
945 WASIRights::FD_TELL | WASIRights::FD_SEEK
946 };
947
948 self.right.can(required_rigth)?;
949
950 let pos = match whence {
951 wasi_types::__wasi_whence_t::__WASI_WHENCE_CUR => SeekFrom::Current(offset),
952 wasi_types::__wasi_whence_t::__WASI_WHENCE_END => SeekFrom::End(offset),
953 wasi_types::__wasi_whence_t::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64),
954 _ => return Err(Errno::__WASI_ERRNO_INVAL),
955 };
956
957 Ok(self.fd.seek(pos)?)
958 }
959
960 fn fd_tell(&mut self) -> Result<wasi_types::__wasi_filesize_t, Errno> {
961 use std::io::SeekFrom;
962 self.right.can(WASIRights::FD_TELL)?;
963 Ok(self.fd.stream_position()?)
964 }
965}
966
967pub enum DiskInode {
968 Dir(DiskDir),
969 File(DiskFile),
970}
971
972impl WasiNode for DiskInode {
973 fn fd_fdstat_get(&self) -> Result<FdStat, Errno> {
974 match self {
975 DiskInode::Dir(inode) => inode.fd_fdstat_get(),
976 DiskInode::File(inode) => inode.fd_fdstat_get(),
977 }
978 }
979
980 fn fd_fdstat_set_flags(&mut self, flags: FdFlags) -> Result<(), Errno> {
981 match self {
982 DiskInode::Dir(inode) => inode.fd_fdstat_set_flags(flags),
983 DiskInode::File(inode) => inode.fd_fdstat_set_flags(flags),
984 }
985 }
986
987 fn fd_fdstat_set_rights(
988 &mut self,
989 fs_rights_base: WASIRights,
990 fs_rights_inheriting: WASIRights,
991 ) -> Result<(), Errno> {
992 match self {
993 DiskInode::Dir(inode) => {
994 inode.fd_fdstat_set_rights(fs_rights_base, fs_rights_inheriting)
995 }
996 DiskInode::File(inode) => {
997 inode.fd_fdstat_set_rights(fs_rights_base, fs_rights_inheriting)
998 }
999 }
1000 }
1001
1002 fn fd_filestat_get(&self) -> Result<Filestat, Errno> {
1003 match self {
1004 DiskInode::Dir(inode) => inode.fd_filestat_get(),
1005 DiskInode::File(inode) => inode.fd_filestat_get(),
1006 }
1007 }
1008
1009 fn fd_filestat_set_size(&mut self, size: wasi_types::__wasi_filesize_t) -> Result<(), Errno> {
1010 match self {
1011 DiskInode::Dir(inode) => inode.fd_filestat_set_size(size),
1012 DiskInode::File(inode) => inode.fd_filestat_set_size(size),
1013 }
1014 }
1015
1016 fn fd_filestat_set_times(
1017 &mut self,
1018 atim: wasi_types::__wasi_timestamp_t,
1019 mtim: wasi_types::__wasi_timestamp_t,
1020 fst_flags: wasi_types::__wasi_fstflags_t::Type,
1021 ) -> Result<(), Errno> {
1022 match self {
1023 DiskInode::Dir(inode) => inode.fd_filestat_set_times(atim, mtim, fst_flags),
1024 DiskInode::File(inode) => inode.fd_filestat_set_times(atim, mtim, fst_flags),
1025 }
1026 }
1027}
1028
1029pub struct DiskFileSys {
1030 real_path: PathBuf,
1031 inodes: slab::Slab<DiskInode>,
1032 dir_rights: WASIRights,
1033 file_rights: WASIRights,
1034}
1035
1036impl DiskFileSys {
1037 pub fn new(host_path: PathBuf) -> std::io::Result<Self> {
1038 let host_path = host_path.canonicalize()?;
1039 let mut inodes = Slab::new();
1040
1041 inodes.insert(DiskInode::Dir(DiskDir {
1042 real_path: host_path.clone(),
1043 dir_rights: WASIRights::dir_all(),
1044 file_rights: WASIRights::fd_all(),
1045 }));
1046
1047 Ok(DiskFileSys {
1048 inodes,
1049 real_path: host_path,
1050 dir_rights: WASIRights::dir_all(),
1051 file_rights: WASIRights::fd_all(),
1052 })
1053 }
1054
1055 pub fn get_absolutize_path<P: AsRef<Path>>(&self, sub_path: &P) -> Result<PathBuf, Errno> {
1056 use path_absolutize::*;
1057 let new_path = self.real_path.join(sub_path);
1058 let absolutize = new_path
1059 .absolutize_virtually(&self.real_path)
1060 .or(Err(Errno::__WASI_ERRNO_NOENT))?;
1061 Ok(absolutize.to_path_buf())
1062 }
1063}
1064
1065impl WasiFileSys for DiskFileSys {
1066 type Index = usize;
1067
1068 fn path_open(
1069 &mut self,
1070 dir_ino: Self::Index,
1071 path: &str,
1072 oflags: OFlags,
1073 fs_rights_base: WASIRights,
1074 fs_rights_inheriting: WASIRights,
1075 fdflags: FdFlags,
1076 ) -> Result<Self::Index, Errno> {
1077 if fdflags.intersects(FdFlags::DSYNC | FdFlags::SYNC | FdFlags::RSYNC) {
1078 return Err(Errno::__WASI_ERRNO_NOSYS);
1079 }
1080
1081 if oflags.intersects(OFlags::DIRECTORY)
1082 && (oflags.contains(OFlags::CREATE)
1083 || oflags.contains(OFlags::EXCLUSIVE)
1084 || oflags.contains(OFlags::TRUNCATE))
1085 {
1086 return Err(Errno::__WASI_ERRNO_INVAL);
1087 }
1088
1089 let parent_dir = match self.inodes.get(dir_ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1090 DiskInode::Dir(dir) => dir,
1091 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1092 };
1093
1094 let path = parent_dir.get_absolutize_path(&path)?;
1095 if path == self.real_path {
1096 return Ok(0);
1097 }
1098
1099 log::trace!("DiskFileSys path_open({path:?},{oflags:?})");
1100
1101 let path_meta = std::fs::metadata(&path).ok();
1102 match path_meta {
1103 Some(meta) if meta.is_dir() => {
1104 let dir_rights = self.dir_rights.clone() & fs_rights_base;
1105 let file_rights = self.file_rights.clone() & fs_rights_inheriting;
1106 let ino = self.inodes.insert(DiskInode::Dir(DiskDir {
1107 real_path: path,
1108 dir_rights,
1109 file_rights,
1110 }));
1111 return Ok(ino);
1112 }
1113 _ => {
1114 if oflags.contains(OFlags::DIRECTORY) {
1115 return Err(Errno::__WASI_ERRNO_NOTDIR);
1116 }
1117 }
1118 }
1119
1120 let read = fs_rights_base.contains(WASIRights::FD_READ);
1121 let write = fs_rights_base.contains(WASIRights::FD_WRITE);
1122
1123 let mut opts = std::fs::OpenOptions::new();
1124
1125 if oflags.contains(OFlags::CREATE | OFlags::EXCLUSIVE) {
1126 opts.create_new(true);
1127 opts.write(true);
1128 } else if oflags.contains(OFlags::CREATE) {
1129 opts.create(true);
1130 opts.write(true);
1131 }
1132
1133 if oflags.contains(OFlags::TRUNCATE) {
1134 opts.truncate(true);
1135 }
1136 if read {
1137 opts.read(true);
1138 }
1139
1140 if write {
1141 opts.write(true);
1142 } else {
1143 opts.read(true);
1144 }
1145
1146 if fdflags.contains(FdFlags::APPEND) {
1147 opts.append(true);
1148 }
1149
1150 let fd = opts.open(path)?;
1151
1152 let ino = self.inodes.insert(DiskInode::File(DiskFile {
1153 fd,
1154 flags: fdflags,
1155 right: fs_rights_base,
1156 }));
1157
1158 Ok(ino)
1159 }
1160
1161 fn path_rename(
1162 &mut self,
1163 old_dir: usize,
1164 old_path: &str,
1165 new_dir: usize,
1166 new_path: &str,
1167 ) -> Result<(), Errno> {
1168 let old_parent_dir = match self.inodes.get(old_dir).ok_or(Errno::__WASI_ERRNO_BADF)? {
1169 DiskInode::Dir(dir) => dir,
1170 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1171 };
1172
1173 let old_path = old_parent_dir.get_absolutize_path(&old_path)?;
1174
1175 let new_parent_dir = match self.inodes.get(new_dir).ok_or(Errno::__WASI_ERRNO_BADF)? {
1176 DiskInode::Dir(dir) => dir,
1177 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1178 };
1179 let new_path = new_parent_dir.get_absolutize_path(&new_path)?;
1180
1181 Ok(std::fs::rename(old_path, new_path)?)
1182 }
1183
1184 fn path_create_directory(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
1185 self.dir_rights.can(WASIRights::PATH_CREATE_DIRECTORY)?;
1186 let parent_dir = match self.inodes.get(dir_ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1187 DiskInode::Dir(dir) => dir,
1188 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1189 };
1190 let new_path = parent_dir.get_absolutize_path(&path)?;
1191 std::fs::DirBuilder::new()
1192 .recursive(true)
1193 .create(new_path)?;
1194 Ok(())
1195 }
1196
1197 fn path_remove_directory(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
1198 self.dir_rights.can(WASIRights::PATH_REMOVE_DIRECTORY)?;
1199 let parent_dir = match self.inodes.get(dir_ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1200 DiskInode::Dir(dir) => dir,
1201 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1202 };
1203 let new_path = parent_dir.get_absolutize_path(&path)?;
1204 log::trace!("DiskFileSys path_remove_directory {new_path:?}");
1205 std::fs::remove_dir(new_path)?;
1206 Ok(())
1207 }
1208
1209 fn path_unlink_file(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
1210 self.dir_rights.can(WASIRights::PATH_REMOVE_DIRECTORY)?;
1211 let parent_dir = match self.inodes.get(dir_ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1212 DiskInode::Dir(dir) => dir,
1213 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1214 };
1215 let new_path = parent_dir.get_absolutize_path(&path)?;
1216 std::fs::remove_file(new_path)?;
1217 Ok(())
1218 }
1219
1220 fn path_link_file(
1221 &mut self,
1222 old_dir: Self::Index,
1223 old_path: &str,
1224 new_dir: Self::Index,
1225 new_path: &str,
1226 ) -> Result<(), Errno> {
1227 Err(Errno::__WASI_ERRNO_NOSYS)
1228 }
1229
1230 fn path_filestat_get(
1231 &self,
1232 dir_ino: Self::Index,
1233 path: &str,
1234 follow_symlinks: bool,
1235 ) -> Result<Filestat, Errno> {
1236 self.dir_rights.can(WASIRights::PATH_FILESTAT_GET)?;
1237
1238 let parent_dir = match self.inodes.get(dir_ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1239 DiskInode::Dir(dir) => dir,
1240 _ => return Err(Errno::__WASI_ERRNO_NOTDIR),
1241 };
1242 let new_path = parent_dir.get_absolutize_path(&path)?;
1243
1244 let meta = if follow_symlinks {
1245 std::fs::metadata(new_path)?
1246 } else {
1247 std::fs::symlink_metadata(new_path)?
1248 };
1249
1250 let filetype = if meta.is_symlink() {
1251 FileType::SYMBOLIC_LINK
1252 } else if meta.is_dir() {
1253 FileType::DIRECTORY
1254 } else {
1255 FileType::REGULAR_FILE
1256 };
1257
1258 let nlink = get_file_nlink(&meta);
1259 let inode = get_file_ino(&meta);
1260
1261 Ok(Filestat {
1262 filetype,
1263 inode,
1264 nlink,
1265 size: meta.len(),
1266 atim: meta.accessed().ok(),
1267 mtim: meta.modified().ok(),
1268 ctim: meta.created().ok(),
1269 })
1270 }
1271
1272 fn fclose(&mut self, ino: Self::Index) -> Result<(), Errno> {
1273 self.inodes.try_remove(ino);
1274 Ok(())
1275 }
1276
1277 fn get_mut_inode(&mut self, ino: usize) -> Result<&mut dyn WasiNode, Errno> {
1278 Ok(self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)?)
1279 }
1280
1281 fn get_inode(&self, ino: usize) -> Result<&dyn WasiNode, Errno> {
1282 Ok(self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_BADF)?)
1283 }
1284
1285 fn get_mut_file(&mut self, ino: usize) -> Result<&mut dyn WasiFile, Errno> {
1286 match self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1287 DiskInode::File(f) => Ok(f),
1288 _ => Err(Errno::__WASI_ERRNO_ISDIR),
1289 }
1290 }
1291
1292 fn get_file(&self, ino: usize) -> Result<&dyn WasiFile, Errno> {
1293 match self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1294 DiskInode::File(f) => Ok(f),
1295 _ => Err(Errno::__WASI_ERRNO_ISDIR),
1296 }
1297 }
1298
1299 fn get_mut_dir(&mut self, ino: usize) -> Result<&mut dyn WasiDir, Errno> {
1300 match self.inodes.get_mut(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1301 DiskInode::Dir(dir) => Ok(dir),
1302 _ => Err(Errno::__WASI_ERRNO_NOTDIR),
1303 }
1304 }
1305
1306 fn get_dir(&self, ino: usize) -> Result<&dyn WasiDir, Errno> {
1307 match self.inodes.get(ino).ok_or(Errno::__WASI_ERRNO_BADF)? {
1308 DiskInode::Dir(dir) => Ok(dir),
1309 _ => Err(Errno::__WASI_ERRNO_NOTDIR),
1310 }
1311 }
1312}
1313
1314pub struct OutPipeline<W: Write>(W);
1316impl<W: Write> From<W> for OutPipeline<W> {
1317 fn from(value: W) -> Self {
1318 Self(value)
1319 }
1320}
1321impl<W: Write> WasiNode for OutPipeline<W> {
1322 fn fd_fdstat_get(&self) -> Result<FdStat, Errno> {
1323 Ok(FdStat {
1324 filetype: FileType::CHARACTER_DEVICE,
1325 fs_rights_base: WASIRights::FD_WRITE | WASIRights::POLL_FD_READWRITE,
1326 fs_rights_inheriting: WASIRights::empty(),
1327 flags: FdFlags::APPEND,
1328 })
1329 }
1330
1331 fn fd_fdstat_set_flags(&mut self, flags: FdFlags) -> Result<(), Errno> {
1332 Err(Errno::__WASI_ERRNO_BADF)
1333 }
1334
1335 fn fd_fdstat_set_rights(
1336 &mut self,
1337 fs_rights_base: WASIRights,
1338 _fs_rights_inheriting: WASIRights,
1339 ) -> Result<(), Errno> {
1340 Err(Errno::__WASI_ERRNO_BADF)
1341 }
1342
1343 fn fd_filestat_get(&self) -> Result<Filestat, Errno> {
1344 Ok(Filestat {
1345 filetype: FileType::CHARACTER_DEVICE,
1346 nlink: 0,
1347 inode: 0,
1348 size: 0,
1349 atim: None,
1350 mtim: None,
1351 ctim: None,
1352 })
1353 }
1354
1355 fn fd_filestat_set_size(&mut self, size: wasi_types::__wasi_filesize_t) -> Result<(), Errno> {
1356 Err(Errno::__WASI_ERRNO_BADF)
1357 }
1358
1359 fn fd_filestat_set_times(
1360 &mut self,
1361 atim: wasi_types::__wasi_timestamp_t,
1362 mtim: wasi_types::__wasi_timestamp_t,
1363 fst_flags: wasi_types::__wasi_fstflags_t::Type,
1364 ) -> Result<(), Errno> {
1365 Err(Errno::__WASI_ERRNO_BADF)
1366 }
1367}
1368impl<W: Write> WasiFile for OutPipeline<W> {
1369 fn fd_advise(
1370 &mut self,
1371 offset: wasi_types::__wasi_filesize_t,
1372 len: wasi_types::__wasi_filesize_t,
1373 advice: Advice,
1374 ) -> Result<(), Errno> {
1375 Ok(())
1376 }
1377
1378 fn fd_allocate(
1379 &mut self,
1380 offset: wasi_types::__wasi_filesize_t,
1381 len: wasi_types::__wasi_filesize_t,
1382 ) -> Result<(), Errno> {
1383 Err(Errno::__WASI_ERRNO_BADF)
1384 }
1385
1386 fn fd_datasync(&mut self) -> Result<(), Errno> {
1387 self.0.flush()?;
1388 Ok(())
1389 }
1390
1391 fn fd_sync(&mut self) -> Result<(), Errno> {
1392 self.0.flush()?;
1393 Ok(())
1394 }
1395
1396 fn fd_read(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> Result<usize, Errno> {
1397 Err(Errno::__WASI_ERRNO_BADF)
1398 }
1399
1400 fn fd_pread(
1401 &mut self,
1402 bufs: &mut [std::io::IoSliceMut<'_>],
1403 offset: wasi_types::__wasi_filesize_t,
1404 ) -> Result<usize, Errno> {
1405 Err(Errno::__WASI_ERRNO_BADF)
1406 }
1407
1408 fn fd_write(&mut self, bufs: &[std::io::IoSlice<'_>]) -> Result<usize, Errno> {
1409 Ok(self.0.write_vectored(bufs)?)
1410 }
1411
1412 fn fd_pwrite(
1413 &mut self,
1414 bufs: &[std::io::IoSlice<'_>],
1415 offset: wasi_types::__wasi_filesize_t,
1416 ) -> Result<usize, Errno> {
1417 Err(Errno::__WASI_ERRNO_SPIPE)
1418 }
1419
1420 fn fd_seek(
1421 &mut self,
1422 offset: wasi_types::__wasi_filedelta_t,
1423 whence: wasi_types::__wasi_whence_t::Type,
1424 ) -> Result<wasi_types::__wasi_filesize_t, Errno> {
1425 Err(Errno::__WASI_ERRNO_SPIPE)
1426 }
1427
1428 fn fd_tell(&mut self) -> Result<wasi_types::__wasi_filesize_t, Errno> {
1429 Err(Errno::__WASI_ERRNO_SPIPE)
1430 }
1431}
1432
1433pub struct InPipline<R: Read>(R);
1434impl<R: Read> From<R> for InPipline<R> {
1435 fn from(value: R) -> Self {
1436 Self(value)
1437 }
1438}
1439impl<R: Read> WasiNode for InPipline<R> {
1440 fn fd_fdstat_get(&self) -> Result<FdStat, Errno> {
1441 Ok(FdStat {
1442 filetype: FileType::CHARACTER_DEVICE,
1443 fs_rights_base: WASIRights::FD_READ | WASIRights::POLL_FD_READWRITE,
1444 fs_rights_inheriting: WASIRights::empty(),
1445 flags: FdFlags::empty(),
1446 })
1447 }
1448
1449 fn fd_fdstat_set_flags(&mut self, flags: FdFlags) -> Result<(), Errno> {
1450 Err(Errno::__WASI_ERRNO_BADF)
1451 }
1452
1453 fn fd_fdstat_set_rights(
1454 &mut self,
1455 fs_rights_base: WASIRights,
1456 _fs_rights_inheriting: WASIRights,
1457 ) -> Result<(), Errno> {
1458 Err(Errno::__WASI_ERRNO_BADF)
1459 }
1460
1461 fn fd_filestat_get(&self) -> Result<Filestat, Errno> {
1462 Ok(Filestat {
1463 filetype: FileType::CHARACTER_DEVICE,
1464 nlink: 0,
1465 inode: 0,
1466 size: 0,
1467 atim: None,
1468 mtim: None,
1469 ctim: None,
1470 })
1471 }
1472
1473 fn fd_filestat_set_size(&mut self, size: wasi_types::__wasi_filesize_t) -> Result<(), Errno> {
1474 Err(Errno::__WASI_ERRNO_BADF)
1475 }
1476
1477 fn fd_filestat_set_times(
1478 &mut self,
1479 atim: wasi_types::__wasi_timestamp_t,
1480 mtim: wasi_types::__wasi_timestamp_t,
1481 fst_flags: wasi_types::__wasi_fstflags_t::Type,
1482 ) -> Result<(), Errno> {
1483 Err(Errno::__WASI_ERRNO_BADF)
1484 }
1485}
1486impl<R: Read> WasiFile for InPipline<R> {
1487 fn fd_advise(
1488 &mut self,
1489 offset: wasi_types::__wasi_filesize_t,
1490 len: wasi_types::__wasi_filesize_t,
1491 advice: Advice,
1492 ) -> Result<(), Errno> {
1493 Ok(())
1494 }
1495
1496 fn fd_allocate(
1497 &mut self,
1498 offset: wasi_types::__wasi_filesize_t,
1499 len: wasi_types::__wasi_filesize_t,
1500 ) -> Result<(), Errno> {
1501 Err(Errno::__WASI_ERRNO_BADF)
1502 }
1503
1504 fn fd_datasync(&mut self) -> Result<(), Errno> {
1505 Ok(())
1506 }
1507
1508 fn fd_sync(&mut self) -> Result<(), Errno> {
1509 Ok(())
1510 }
1511
1512 fn fd_read(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> Result<usize, Errno> {
1513 Ok(self.0.read_vectored(bufs)?)
1514 }
1515
1516 fn fd_pread(
1517 &mut self,
1518 bufs: &mut [std::io::IoSliceMut<'_>],
1519 offset: wasi_types::__wasi_filesize_t,
1520 ) -> Result<usize, Errno> {
1521 Err(Errno::__WASI_ERRNO_SPIPE)
1522 }
1523
1524 fn fd_write(&mut self, bufs: &[std::io::IoSlice<'_>]) -> Result<usize, Errno> {
1525 Err(Errno::__WASI_ERRNO_BADF)
1526 }
1527
1528 fn fd_pwrite(
1529 &mut self,
1530 bufs: &[std::io::IoSlice<'_>],
1531 offset: wasi_types::__wasi_filesize_t,
1532 ) -> Result<usize, Errno> {
1533 Err(Errno::__WASI_ERRNO_BADF)
1534 }
1535
1536 fn fd_seek(
1537 &mut self,
1538 offset: wasi_types::__wasi_filedelta_t,
1539 whence: wasi_types::__wasi_whence_t::Type,
1540 ) -> Result<wasi_types::__wasi_filesize_t, Errno> {
1541 Err(Errno::__WASI_ERRNO_SPIPE)
1542 }
1543
1544 fn fd_tell(&mut self) -> Result<wasi_types::__wasi_filesize_t, Errno> {
1545 Err(Errno::__WASI_ERRNO_SPIPE)
1546 }
1547}
1548
1549pub struct StdioSys<IN, OUT, ERR>
1550where
1551 IN: std::io::Read,
1552 OUT: std::io::Write,
1553 ERR: std::io::Write,
1554{
1555 stdin: InPipline<IN>,
1556 stdout: OutPipeline<OUT>,
1557 stderr: OutPipeline<ERR>,
1558}
1559
1560impl<IN, OUT, ERR> StdioSys<IN, OUT, ERR>
1561where
1562 IN: std::io::Read,
1563 OUT: std::io::Write,
1564 ERR: std::io::Write,
1565{
1566 pub fn new(stdin: IN, stdout: OUT, stderr: ERR) -> Self {
1567 Self {
1568 stdin: InPipline(stdin),
1569 stdout: OutPipeline(stdout),
1570 stderr: OutPipeline(stderr),
1571 }
1572 }
1573}
1574
1575impl<IN, OUT, ERR> WasiFileSys for StdioSys<IN, OUT, ERR>
1576where
1577 IN: std::io::Read,
1578 OUT: std::io::Write,
1579 ERR: std::io::Write,
1580{
1581 type Index = usize;
1582
1583 fn path_open(
1584 &mut self,
1585 dir_ino: usize,
1586 path: &str,
1587 oflags: OFlags,
1588 fs_rights_base: WASIRights,
1589 fs_rights_inheriting: WASIRights,
1590 fdflags: FdFlags,
1591 ) -> Result<Self::Index, Errno> {
1592 Err(Errno::__WASI_ERRNO_BADF)
1593 }
1594
1595 fn path_rename(
1596 &mut self,
1597 old_dir: usize,
1598 old_path: &str,
1599 new_dir: usize,
1600 new_path: &str,
1601 ) -> Result<(), Errno> {
1602 Err(Errno::__WASI_ERRNO_BADF)
1603 }
1604
1605 fn path_create_directory(&mut self, dir_ino: usize, path: &str) -> Result<(), Errno> {
1606 Err(Errno::__WASI_ERRNO_BADF)
1607 }
1608
1609 fn path_remove_directory(&mut self, dir_ino: usize, path: &str) -> Result<(), Errno> {
1610 Err(Errno::__WASI_ERRNO_BADF)
1611 }
1612
1613 fn path_unlink_file(&mut self, dir_ino: Self::Index, path: &str) -> Result<(), Errno> {
1614 Err(Errno::__WASI_ERRNO_BADF)
1615 }
1616
1617 fn path_link_file(
1618 &mut self,
1619 old_dir: Self::Index,
1620 old_path: &str,
1621 new_dir: Self::Index,
1622 new_path: &str,
1623 ) -> Result<(), Errno> {
1624 Err(Errno::__WASI_ERRNO_BADF)
1625 }
1626
1627 fn path_filestat_get(
1628 &self,
1629 dir_ino: usize,
1630 path: &str,
1631 follow_symlinks: bool,
1632 ) -> Result<Filestat, Errno> {
1633 Err(Errno::__WASI_ERRNO_BADF)
1634 }
1635
1636 fn get_mut_inode(&mut self, ino: usize) -> Result<&mut dyn WasiNode, Errno> {
1637 match ino {
1638 0 => Ok(&mut self.stdin),
1639 1 => Ok(&mut self.stdout),
1640 2 => Ok(&mut self.stderr),
1641 _ => Err(Errno::__WASI_ERRNO_BADF),
1642 }
1643 }
1644
1645 fn get_inode(&self, ino: usize) -> Result<&dyn WasiNode, Errno> {
1646 match ino {
1647 0 => Ok(&self.stdin),
1648 1 => Ok(&self.stdout),
1649 2 => Ok(&self.stderr),
1650 _ => Err(Errno::__WASI_ERRNO_BADF),
1651 }
1652 }
1653
1654 fn get_mut_file(&mut self, ino: usize) -> Result<&mut dyn WasiFile, Errno> {
1655 match ino {
1656 0 => Ok(&mut self.stdin),
1657 1 => Ok(&mut self.stdout),
1658 2 => Ok(&mut self.stderr),
1659 _ => Err(Errno::__WASI_ERRNO_BADF),
1660 }
1661 }
1662
1663 fn get_file(&self, ino: usize) -> Result<&dyn WasiFile, Errno> {
1664 match ino {
1665 0 => Ok(&self.stdin),
1666 1 => Ok(&self.stdout),
1667 2 => Ok(&self.stderr),
1668 _ => Err(Errno::__WASI_ERRNO_BADF),
1669 }
1670 }
1671
1672 fn get_mut_dir(&mut self, ino: usize) -> Result<&mut dyn WasiDir, Errno> {
1673 Err(Errno::__WASI_ERRNO_NOTDIR)
1674 }
1675
1676 fn get_dir(&self, ino: usize) -> Result<&dyn WasiDir, Errno> {
1677 Err(Errno::__WASI_ERRNO_NOTDIR)
1678 }
1679}