1use std::any::Any;
2use std::cmp::min;
3use std::io::{IoSlice, IoSliceMut, SeekFrom};
4use std::ops::{Deref, DerefMut};
5use std::sync::Arc;
6
7use wasi_common::file::{Advice, FdFlags, FileType, Filestat};
8use wasi_common::{Error, ErrorExt, ErrorKind, SystemTimeSpec, WasiDir, WasiFile};
9use wasmtime_vfs_ledger::InodeId;
10use wasmtime_vfs_memory::{Data, Inode, Link, Node, Open, State};
11
12pub struct File(Link<Vec<u8>>);
13
14impl Deref for File {
15 type Target = Link<Vec<u8>>;
16
17 fn deref(&self) -> &Self::Target {
18 &self.0
19 }
20}
21
22impl DerefMut for File {
23 fn deref_mut(&mut self) -> &mut Self::Target {
24 &mut self.0
25 }
26}
27
28#[async_trait::async_trait]
29impl Node for File {
30 fn to_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
31 self
32 }
33
34 fn parent(&self) -> Option<Arc<dyn Node>> {
35 self.parent.upgrade()
36 }
37
38 fn filetype(&self) -> FileType {
39 FileType::RegularFile
40 }
41
42 fn id(&self) -> Arc<InodeId> {
43 self.inode.id.clone()
44 }
45
46 async fn open_dir(self: Arc<Self>) -> Result<Box<dyn WasiDir>, Error> {
47 Err(Error::not_dir())
48 }
49
50 async fn open_file(
51 self: Arc<Self>,
52 _path: &str,
53 dir: bool,
54 read: bool,
55 write: bool,
56 flags: FdFlags,
57 ) -> Result<Box<dyn WasiFile>, Error> {
58 if dir {
59 return Err(Error::not_dir());
60 }
61
62 Ok(Box::new(OpenFile(Open {
63 root: self.root(),
64 link: self,
65 state: State::from(flags).into(),
66 write,
67 read,
68 })))
69 }
70}
71
72impl File {
73 #[allow(clippy::new_ret_no_self)]
74 pub fn new(parent: Arc<dyn Node>) -> Arc<dyn Node> {
75 Self::with_data(parent, [])
76 }
77
78 pub fn with_data(parent: Arc<dyn Node>, data: impl Into<Vec<u8>>) -> Arc<dyn Node> {
79 let id = parent.id().device().create_inode();
80
81 let inode = Inode {
82 data: Data::from(data.into()).into(),
83 id,
84 };
85
86 Arc::new(Self(Link {
87 parent: Arc::downgrade(&parent),
88 inode: inode.into(),
89 }))
90 }
91}
92
93struct OpenFile(Open<File>);
94
95impl Deref for OpenFile {
96 type Target = Open<File>;
97
98 fn deref(&self) -> &Self::Target {
99 &self.0
100 }
101}
102
103#[async_trait::async_trait]
104impl WasiFile for OpenFile {
105 fn as_any(&self) -> &dyn Any {
106 self
107 }
108
109 async fn get_filetype(&mut self) -> Result<FileType, Error> {
110 Ok(FileType::RegularFile)
111 }
112
113 async fn datasync(&mut self) -> Result<(), Error> {
114 Ok(())
115 }
116
117 async fn sync(&mut self) -> Result<(), Error> {
118 Ok(())
119 }
120
121 async fn get_fdflags(&mut self) -> Result<FdFlags, Error> {
122 Ok(self.state.read().await.flags)
123 }
124
125 async fn set_fdflags(&mut self, flags: FdFlags) -> Result<(), Error> {
126 if !self.write {
127 return Err(Error::io()); }
129
130 self.state.write().await.flags = flags;
131 Ok(())
132 }
133
134 async fn get_filestat(&mut self) -> Result<Filestat, Error> {
135 let ilock = self.link.inode.data.read().await;
136
137 Ok(Filestat {
138 device_id: **self.link.inode.id.device(),
139 inode: **self.link.inode.id,
140 filetype: FileType::RegularFile,
141 nlink: Arc::strong_count(&self.link.inode) as u64,
142 size: ilock.content.len() as u64,
143 atim: Some(ilock.access),
144 mtim: Some(ilock.modify),
145 ctim: Some(ilock.create),
146 })
147 }
148
149 async fn set_filestat_size(&mut self, size: u64) -> Result<(), Error> {
150 let size: usize = size.try_into().map_err(|_| Error::invalid_argument())?;
151
152 if !self.write {
153 return Err(Error::io()); }
155
156 self.link.inode.data.write().await.content.resize(size, 0);
157 Ok(())
158 }
159
160 async fn advise(&mut self, _offset: u64, _len: u64, _advice: Advice) -> Result<(), Error> {
161 Ok(())
162 }
163
164 async fn allocate(&mut self, offset: u64, len: u64) -> Result<(), Error> {
165 if !self.write {
166 return Err(Error::io()); }
168
169 let offset: usize = offset.try_into().map_err(|_| Error::invalid_argument())?;
170 let len: usize = len.try_into().map_err(|_| Error::invalid_argument())?;
171 offset
172 .checked_add(len)
173 .ok_or_else(Error::invalid_argument)?;
174 Ok(())
175 }
176
177 async fn set_times(
178 &mut self,
179 atime: Option<SystemTimeSpec>,
180 mtime: Option<SystemTimeSpec>,
181 ) -> Result<(), Error> {
182 if !self.write {
183 return Err(Error::io()); }
185
186 self.link.inode.data.write().await.set_times(atime, mtime)
187 }
188
189 async fn read_vectored<'a>(&mut self, bufs: &mut [IoSliceMut<'a>]) -> Result<u64, Error> {
190 if !self.read {
191 return Err(Error::io()); }
193
194 let mut total = 0;
195
196 let mut olock = self.state.write().await;
197 let ilock = self.link.inode.data.read().await;
198 for buf in bufs {
199 let len = min(buf.len(), ilock.content.len() - olock.pos);
200 buf[..len].copy_from_slice(&ilock.content[olock.pos..][..len]);
201 total += len as u64;
202 olock.pos += len;
203 }
204
205 Ok(total)
206 }
207
208 async fn read_vectored_at<'a>(
209 &mut self,
210 bufs: &mut [IoSliceMut<'a>],
211 offset: u64,
212 ) -> Result<u64, Error> {
213 if !self.read {
214 return Err(Error::io()); }
216
217 let mut position: usize = offset.try_into().map_err(|_| Error::invalid_argument())?;
218 let mut total = 0;
219
220 let data = &self.link.inode.data.read().await.content[..];
221 for buf in bufs {
222 let len = min(buf.len(), data.len() - position);
223 buf[..len].copy_from_slice(&data[position..][..len]);
224 total += len as u64;
225 position += len;
226 }
227
228 Ok(total)
229 }
230
231 async fn write_vectored<'a>(&mut self, bufs: &[IoSlice<'a>]) -> Result<u64, Error> {
232 if !self.write {
233 return Err(Error::io()); }
235
236 let mut total = 0;
237
238 let mut olock = self.state.write().await;
239 let mut ilock = self.link.inode.data.write().await;
240 for buf in bufs {
241 let pos = match olock.flags.contains(FdFlags::APPEND) {
242 true => ilock.content.len(),
243 false => olock.pos,
244 };
245
246 if pos + buf.len() > ilock.content.len() {
247 ilock.content.resize(pos + buf.len(), 0);
248 }
249
250 ilock.content[pos..][..buf.len()].copy_from_slice(buf);
251 total += buf.len() as u64;
252
253 if !olock.flags.contains(FdFlags::APPEND) {
254 olock.pos += buf.len();
255 }
256 }
257
258 Ok(total)
259 }
260
261 async fn write_vectored_at<'a>(
265 &mut self,
266 bufs: &[IoSlice<'a>],
267 offset: u64,
268 ) -> Result<u64, Error> {
269 if !self.write {
270 return Err(Error::io()); }
272
273 let mut pos: usize = offset.try_into().map_err(|_| Error::invalid_argument())?;
274 let mut total = 0;
275
276 let mut ilock = self.link.inode.data.write().await;
277 for buf in bufs {
278 if pos + buf.len() > ilock.content.len() {
279 ilock.content.resize(pos + buf.len(), 0);
280 }
281
282 ilock.content[pos..][..buf.len()].copy_from_slice(buf);
283 total += buf.len() as u64;
284 pos += buf.len();
285 }
286
287 Ok(total)
288 }
289
290 async fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
291 let mut olock = self.state.write().await;
292 let ilock = self.link.inode.data.read().await;
293
294 let cur = match pos {
295 SeekFrom::Current(_) => i64::try_from(olock.pos),
296 SeekFrom::Start(_) => Ok(0),
297 SeekFrom::End(_) => i64::try_from(ilock.content.len()),
298 };
299
300 let off = match pos {
301 SeekFrom::Current(off) => Ok(off),
302 SeekFrom::Start(off) => i64::try_from(off),
303 SeekFrom::End(off) => Ok(off),
304 };
305
306 let pos = cur.map_err(|_| ErrorKind::Inval)? + off.map_err(|_| ErrorKind::Inval)?;
307 let pos = usize::try_from(pos).map_err(|_| ErrorKind::Inval)?;
308 olock.pos = pos;
309
310 Ok(pos as u64)
311 }
312
313 async fn peek(&mut self, buf: &mut [u8]) -> Result<u64, Error> {
314 if !self.read {
315 return Err(Error::io()); }
317
318 let mut total = 0;
319
320 let olock = self.state.read().await;
321 let ilock = self.link.inode.data.read().await;
322 let len = min(buf.len(), ilock.content.len() - olock.pos);
323 buf[..len].copy_from_slice(&ilock.content[olock.pos..][..len]);
324 total += len as u64;
325
326 Ok(total)
327 }
328
329 async fn num_ready_bytes(&self) -> Result<u64, Error> {
330 if !self.read {
331 return Err(Error::io()); }
333
334 let olock = self.state.read().await;
335 let ilock = self.link.inode.data.read().await;
336 let len = min(ilock.content.len(), olock.pos);
337 let len = ilock.content.len() - len;
338 Ok(len as u64)
339 }
340
341 async fn readable(&self) -> Result<(), Error> {
342 Ok(())
343 }
344
345 async fn writable(&self) -> Result<(), Error> {
346 Ok(())
347 }
348}