wasi_common/
file.rs

1use crate::{Error, ErrorExt, SystemTimeSpec};
2use bitflags::bitflags;
3use std::any::Any;
4use std::sync::Arc;
5
6#[wiggle::async_trait]
7pub trait WasiFile: Send + Sync {
8    fn as_any(&self) -> &dyn Any;
9    async fn get_filetype(&self) -> Result<FileType, Error>;
10
11    #[cfg(unix)]
12    fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
13        None
14    }
15
16    #[cfg(windows)]
17    fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
18        None
19    }
20
21    fn isatty(&self) -> bool {
22        false
23    }
24
25    async fn sock_accept(&self, _fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
26        Err(Error::badf())
27    }
28
29    async fn sock_recv<'a>(
30        &self,
31        _ri_data: &mut [std::io::IoSliceMut<'a>],
32        _ri_flags: RiFlags,
33    ) -> Result<(u64, RoFlags), Error> {
34        Err(Error::badf())
35    }
36
37    async fn sock_send<'a>(
38        &self,
39        _si_data: &[std::io::IoSlice<'a>],
40        _si_flags: SiFlags,
41    ) -> Result<u64, Error> {
42        Err(Error::badf())
43    }
44
45    async fn sock_shutdown(&self, _how: SdFlags) -> Result<(), Error> {
46        Err(Error::badf())
47    }
48
49    async fn datasync(&self) -> Result<(), Error> {
50        Ok(())
51    }
52
53    async fn sync(&self) -> Result<(), Error> {
54        Ok(())
55    }
56
57    async fn get_fdflags(&self) -> Result<FdFlags, Error> {
58        Ok(FdFlags::empty())
59    }
60
61    async fn set_fdflags(&mut self, _flags: FdFlags) -> Result<(), Error> {
62        Err(Error::badf())
63    }
64
65    async fn get_filestat(&self) -> Result<Filestat, Error> {
66        Ok(Filestat {
67            device_id: 0,
68            inode: 0,
69            filetype: self.get_filetype().await?,
70            nlink: 0,
71            size: 0, // XXX no way to get a size out of a Read :(
72            atim: None,
73            mtim: None,
74            ctim: None,
75        })
76    }
77
78    async fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
79        Err(Error::badf())
80    }
81
82    async fn advise(&self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> {
83        Err(Error::badf())
84    }
85
86    async fn set_times(
87        &self,
88        _atime: Option<SystemTimeSpec>,
89        _mtime: Option<SystemTimeSpec>,
90    ) -> Result<(), Error> {
91        Err(Error::badf())
92    }
93
94    async fn read_vectored<'a>(&self, _bufs: &mut [std::io::IoSliceMut<'a>]) -> Result<u64, Error> {
95        Err(Error::badf())
96    }
97
98    async fn read_vectored_at<'a>(
99        &self,
100        _bufs: &mut [std::io::IoSliceMut<'a>],
101        _offset: u64,
102    ) -> Result<u64, Error> {
103        Err(Error::badf())
104    }
105
106    async fn write_vectored<'a>(&self, _bufs: &[std::io::IoSlice<'a>]) -> Result<u64, Error> {
107        Err(Error::badf())
108    }
109
110    async fn write_vectored_at<'a>(
111        &self,
112        _bufs: &[std::io::IoSlice<'a>],
113        _offset: u64,
114    ) -> Result<u64, Error> {
115        Err(Error::badf())
116    }
117
118    async fn seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
119        Err(Error::badf())
120    }
121
122    async fn peek(&self, _buf: &mut [u8]) -> Result<u64, Error> {
123        Err(Error::badf())
124    }
125
126    fn num_ready_bytes(&self) -> Result<u64, Error> {
127        Ok(0)
128    }
129
130    async fn readable(&self) -> Result<(), Error> {
131        Err(Error::badf())
132    }
133
134    async fn writable(&self) -> Result<(), Error> {
135        Err(Error::badf())
136    }
137}
138
139#[derive(Debug, Copy, Clone, PartialEq, Eq)]
140pub enum FileType {
141    Unknown,
142    BlockDevice,
143    CharacterDevice,
144    Directory,
145    RegularFile,
146    SocketDgram,
147    SocketStream,
148    SymbolicLink,
149    Pipe,
150}
151
152bitflags! {
153    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
154    pub struct FdFlags: u32 {
155        const APPEND   = 0b1;
156        const DSYNC    = 0b10;
157        const NONBLOCK = 0b100;
158        const RSYNC    = 0b1000;
159        const SYNC     = 0b10000;
160    }
161}
162
163bitflags! {
164    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
165    pub struct SdFlags: u32 {
166        const RD = 0b1;
167        const WR = 0b10;
168    }
169}
170
171bitflags! {
172    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
173    pub struct SiFlags: u32 {
174    }
175}
176
177bitflags! {
178    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
179    pub struct RiFlags: u32 {
180        const RECV_PEEK    = 0b1;
181        const RECV_WAITALL = 0b10;
182    }
183}
184
185bitflags! {
186    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
187    pub struct RoFlags: u32 {
188        const RECV_DATA_TRUNCATED = 0b1;
189    }
190}
191
192bitflags! {
193    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
194    pub struct OFlags: u32 {
195        const CREATE    = 0b1;
196        const DIRECTORY = 0b10;
197        const EXCLUSIVE = 0b100;
198        const TRUNCATE  = 0b1000;
199    }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq)]
203pub struct Filestat {
204    pub device_id: u64,
205    pub inode: u64,
206    pub filetype: FileType,
207    pub nlink: u64,
208    pub size: u64, // this is a read field, the rest are file fields
209    pub atim: Option<std::time::SystemTime>,
210    pub mtim: Option<std::time::SystemTime>,
211    pub ctim: Option<std::time::SystemTime>,
212}
213
214pub(crate) trait TableFileExt {
215    fn get_file(&self, fd: u32) -> Result<Arc<FileEntry>, Error>;
216    fn get_file_mut(&mut self, fd: u32) -> Result<&mut FileEntry, Error>;
217}
218impl TableFileExt for crate::table::Table {
219    fn get_file(&self, fd: u32) -> Result<Arc<FileEntry>, Error> {
220        self.get(fd)
221    }
222    fn get_file_mut(&mut self, fd: u32) -> Result<&mut FileEntry, Error> {
223        self.get_mut(fd)
224    }
225}
226
227pub(crate) struct FileEntry {
228    pub file: Box<dyn WasiFile>,
229    pub access_mode: FileAccessMode,
230}
231
232bitflags! {
233    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
234    pub struct FileAccessMode : u32 {
235        const READ = 0b1;
236        const WRITE= 0b10;
237    }
238}
239
240impl FileEntry {
241    pub fn new(file: Box<dyn WasiFile>, access_mode: FileAccessMode) -> Self {
242        FileEntry { file, access_mode }
243    }
244
245    pub async fn get_fdstat(&self) -> Result<FdStat, Error> {
246        Ok(FdStat {
247            filetype: self.file.get_filetype().await?,
248            flags: self.file.get_fdflags().await?,
249            access_mode: self.access_mode,
250        })
251    }
252}
253
254#[derive(Debug, Clone)]
255pub struct FdStat {
256    pub filetype: FileType,
257    pub flags: FdFlags,
258    pub access_mode: FileAccessMode,
259}
260
261#[derive(Debug, Clone)]
262pub enum Advice {
263    Normal,
264    Sequential,
265    Random,
266    WillNeed,
267    DontNeed,
268    NoReuse,
269}