1 #![allow(non_camel_case_types)]
2 use super::fs_helpers::path_get;
3 use crate::old::snapshot_0::ctx::WasiCtx;
4 use crate::old::snapshot_0::entry::{Descriptor, Entry};
5 use crate::old::snapshot_0::helpers::*;
6 use crate::old::snapshot_0::memory::*;
7 use crate::old::snapshot_0::sys::entry_impl::determine_type_rights;
8 use crate::old::snapshot_0::sys::hostcalls_impl::fs_helpers::path_open_rights;
9 use crate::old::snapshot_0::sys::{host_impl, hostcalls_impl};
10 use crate::old::snapshot_0::wasi::{self, WasiError, WasiResult};
11 use crate::old::snapshot_0::{helpers, host, wasi32};
12 use crate::sandboxed_tty_writer::SandboxedTTYWriter;
13 use filetime::{set_file_handle_times, FileTime};
14 use log::trace;
15 use std::fs::File;
16 use std::io::{self, Read, Seek, SeekFrom, Write};
17 use std::ops::DerefMut;
18 use std::time::{Duration, SystemTime, UNIX_EPOCH};
19 
fd_close( wasi_ctx: &mut WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, ) -> WasiResult<()>20 pub(crate) unsafe fn fd_close(
21     wasi_ctx: &mut WasiCtx,
22     _mem: &mut [u8],
23     fd: wasi::__wasi_fd_t,
24 ) -> WasiResult<()> {
25     trace!("fd_close(fd={:?})", fd);
26 
27     if let Ok(fe) = wasi_ctx.get_entry(fd) {
28         // can't close preopened files
29         if fe.preopen_path.is_some() {
30             return Err(WasiError::ENOTSUP);
31         }
32     }
33 
34     wasi_ctx.remove_entry(fd)?;
35     Ok(())
36 }
37 
fd_datasync( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, ) -> WasiResult<()>38 pub(crate) unsafe fn fd_datasync(
39     wasi_ctx: &WasiCtx,
40     _mem: &mut [u8],
41     fd: wasi::__wasi_fd_t,
42 ) -> WasiResult<()> {
43     trace!("fd_datasync(fd={:?})", fd);
44 
45     let fd = wasi_ctx
46         .get_entry(fd)?
47         .as_descriptor(wasi::__WASI_RIGHTS_FD_DATASYNC, 0)?
48         .as_file()?;
49 
50     fd.sync_data().map_err(Into::into)
51 }
52 
fd_pread( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, offset: wasi::__wasi_filesize_t, nread: wasi32::uintptr_t, ) -> WasiResult<()>53 pub(crate) unsafe fn fd_pread(
54     wasi_ctx: &WasiCtx,
55     memory: &mut [u8],
56     fd: wasi::__wasi_fd_t,
57     iovs_ptr: wasi32::uintptr_t,
58     iovs_len: wasi32::size_t,
59     offset: wasi::__wasi_filesize_t,
60     nread: wasi32::uintptr_t,
61 ) -> WasiResult<()> {
62     trace!(
63         "fd_pread(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})",
64         fd,
65         iovs_ptr,
66         iovs_len,
67         offset,
68         nread
69     );
70 
71     let fd = wasi_ctx
72         .get_entry(fd)?
73         .as_descriptor(wasi::__WASI_RIGHTS_FD_READ | wasi::__WASI_RIGHTS_FD_SEEK, 0)?
74         .as_file()?;
75 
76     let iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?;
77 
78     if offset > i64::max_value() as u64 {
79         return Err(WasiError::EIO);
80     }
81     let buf_size = iovs.iter().map(|v| v.buf_len).sum();
82     let mut buf = vec![0; buf_size];
83     let host_nread = hostcalls_impl::fd_pread(fd, &mut buf, offset)?;
84     let mut buf_offset = 0;
85     let mut left = host_nread;
86     for iov in &iovs {
87         if left == 0 {
88             break;
89         }
90         let vec_len = std::cmp::min(iov.buf_len, left);
91         std::slice::from_raw_parts_mut(iov.buf as *mut u8, vec_len)
92             .copy_from_slice(&buf[buf_offset..buf_offset + vec_len]);
93         buf_offset += vec_len;
94         left -= vec_len;
95     }
96 
97     trace!("     | *nread={:?}", host_nread);
98 
99     enc_usize_byref(memory, nread, host_nread)
100 }
101 
fd_pwrite( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, offset: wasi::__wasi_filesize_t, nwritten: wasi32::uintptr_t, ) -> WasiResult<()>102 pub(crate) unsafe fn fd_pwrite(
103     wasi_ctx: &WasiCtx,
104     memory: &mut [u8],
105     fd: wasi::__wasi_fd_t,
106     iovs_ptr: wasi32::uintptr_t,
107     iovs_len: wasi32::size_t,
108     offset: wasi::__wasi_filesize_t,
109     nwritten: wasi32::uintptr_t,
110 ) -> WasiResult<()> {
111     trace!(
112         "fd_pwrite(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})",
113         fd,
114         iovs_ptr,
115         iovs_len,
116         offset,
117         nwritten
118     );
119 
120     let fd = wasi_ctx
121         .get_entry(fd)?
122         .as_descriptor(
123             wasi::__WASI_RIGHTS_FD_WRITE | wasi::__WASI_RIGHTS_FD_SEEK,
124             0,
125         )?
126         .as_file()?;
127     let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?;
128 
129     if offset > i64::max_value() as u64 {
130         return Err(WasiError::EIO);
131     }
132     let buf_size = iovs.iter().map(|v| v.buf_len).sum();
133     let mut buf = Vec::with_capacity(buf_size);
134     for iov in &iovs {
135         buf.extend_from_slice(std::slice::from_raw_parts(
136             iov.buf as *const u8,
137             iov.buf_len,
138         ));
139     }
140     let host_nwritten = hostcalls_impl::fd_pwrite(fd, &buf, offset)?;
141 
142     trace!("     | *nwritten={:?}", host_nwritten);
143 
144     enc_usize_byref(memory, nwritten, host_nwritten)
145 }
146 
fd_read( wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, nread: wasi32::uintptr_t, ) -> WasiResult<()>147 pub(crate) unsafe fn fd_read(
148     wasi_ctx: &mut WasiCtx,
149     memory: &mut [u8],
150     fd: wasi::__wasi_fd_t,
151     iovs_ptr: wasi32::uintptr_t,
152     iovs_len: wasi32::size_t,
153     nread: wasi32::uintptr_t,
154 ) -> WasiResult<()> {
155     trace!(
156         "fd_read(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nread={:#x?})",
157         fd,
158         iovs_ptr,
159         iovs_len,
160         nread
161     );
162 
163     let mut iovs = dec_iovec_slice(memory, iovs_ptr, iovs_len)?;
164     let mut iovs: Vec<io::IoSliceMut> = iovs
165         .iter_mut()
166         .map(|vec| host::iovec_to_host_mut(vec))
167         .collect();
168 
169     let maybe_host_nread = match wasi_ctx
170         .get_entry_mut(fd)?
171         .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_READ, 0)?
172     {
173         Descriptor::OsHandle(file) => file.read_vectored(&mut iovs),
174         Descriptor::Stdin => io::stdin().read_vectored(&mut iovs),
175         _ => return Err(WasiError::EBADF),
176     };
177 
178     let host_nread = maybe_host_nread?;
179 
180     trace!("     | *nread={:?}", host_nread);
181 
182     enc_usize_byref(memory, nread, host_nread)
183 }
184 
fd_renumber( wasi_ctx: &mut WasiCtx, _mem: &mut [u8], from: wasi::__wasi_fd_t, to: wasi::__wasi_fd_t, ) -> WasiResult<()>185 pub(crate) unsafe fn fd_renumber(
186     wasi_ctx: &mut WasiCtx,
187     _mem: &mut [u8],
188     from: wasi::__wasi_fd_t,
189     to: wasi::__wasi_fd_t,
190 ) -> WasiResult<()> {
191     trace!("fd_renumber(from={:?}, to={:?})", from, to);
192 
193     if !wasi_ctx.contains_entry(from) {
194         return Err(WasiError::EBADF);
195     }
196 
197     // Don't allow renumbering over a pre-opened resource.
198     // TODO: Eventually, we do want to permit this, once libpreopen in
199     // userspace is capable of removing entries from its tables as well.
200     let from_fe = wasi_ctx.get_entry(from)?;
201     if from_fe.preopen_path.is_some() {
202         return Err(WasiError::ENOTSUP);
203     }
204     if let Ok(to_fe) = wasi_ctx.get_entry(to) {
205         if to_fe.preopen_path.is_some() {
206             return Err(WasiError::ENOTSUP);
207         }
208     }
209 
210     let fe = wasi_ctx.remove_entry(from)?;
211     wasi_ctx.insert_entry_at(to, fe);
212 
213     Ok(())
214 }
215 
fd_seek( wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, offset: wasi::__wasi_filedelta_t, whence: wasi::__wasi_whence_t, newoffset: wasi32::uintptr_t, ) -> WasiResult<()>216 pub(crate) unsafe fn fd_seek(
217     wasi_ctx: &mut WasiCtx,
218     memory: &mut [u8],
219     fd: wasi::__wasi_fd_t,
220     offset: wasi::__wasi_filedelta_t,
221     whence: wasi::__wasi_whence_t,
222     newoffset: wasi32::uintptr_t,
223 ) -> WasiResult<()> {
224     trace!(
225         "fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})",
226         fd,
227         offset,
228         wasi::whence_to_str(whence),
229         newoffset
230     );
231 
232     let rights = if offset == 0 && whence == wasi::__WASI_WHENCE_CUR {
233         wasi::__WASI_RIGHTS_FD_TELL
234     } else {
235         wasi::__WASI_RIGHTS_FD_SEEK | wasi::__WASI_RIGHTS_FD_TELL
236     };
237     let fd = wasi_ctx
238         .get_entry_mut(fd)?
239         .as_descriptor_mut(rights, 0)?
240         .as_file_mut()?;
241 
242     let pos = match whence {
243         wasi::__WASI_WHENCE_CUR => SeekFrom::Current(offset),
244         wasi::__WASI_WHENCE_END => SeekFrom::End(offset),
245         wasi::__WASI_WHENCE_SET => SeekFrom::Start(offset as u64),
246         _ => return Err(WasiError::EINVAL),
247     };
248     let host_newoffset = fd.seek(pos)?;
249 
250     trace!("     | *newoffset={:?}", host_newoffset);
251 
252     enc_filesize_byref(memory, newoffset, host_newoffset)
253 }
254 
fd_tell( wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, newoffset: wasi32::uintptr_t, ) -> WasiResult<()>255 pub(crate) unsafe fn fd_tell(
256     wasi_ctx: &mut WasiCtx,
257     memory: &mut [u8],
258     fd: wasi::__wasi_fd_t,
259     newoffset: wasi32::uintptr_t,
260 ) -> WasiResult<()> {
261     trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset);
262 
263     let fd = wasi_ctx
264         .get_entry_mut(fd)?
265         .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_TELL, 0)?
266         .as_file_mut()?;
267 
268     let host_offset = fd.seek(SeekFrom::Current(0))?;
269 
270     trace!("     | *newoffset={:?}", host_offset);
271 
272     enc_filesize_byref(memory, newoffset, host_offset)
273 }
274 
fd_fdstat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, fdstat_ptr: wasi32::uintptr_t, ) -> WasiResult<()>275 pub(crate) unsafe fn fd_fdstat_get(
276     wasi_ctx: &WasiCtx,
277     memory: &mut [u8],
278     fd: wasi::__wasi_fd_t,
279     fdstat_ptr: wasi32::uintptr_t, // *mut wasi::__wasi_fdstat_t
280 ) -> WasiResult<()> {
281     trace!("fd_fdstat_get(fd={:?}, fdstat_ptr={:#x?})", fd, fdstat_ptr);
282 
283     let mut fdstat = dec_fdstat_byref(memory, fdstat_ptr)?;
284     let host_fd = wasi_ctx.get_entry(fd)?.as_descriptor(0, 0)?.as_os_handle();
285 
286     let fs_flags = hostcalls_impl::fd_fdstat_get(&host_fd)?;
287 
288     let fe = wasi_ctx.get_entry(fd)?;
289     fdstat.fs_filetype = fe.file_type;
290     fdstat.fs_rights_base = fe.rights_base;
291     fdstat.fs_rights_inheriting = fe.rights_inheriting;
292     fdstat.fs_flags = fs_flags;
293 
294     trace!("     | *buf={:?}", fdstat);
295 
296     enc_fdstat_byref(memory, fdstat_ptr, fdstat)
297 }
298 
fd_fdstat_set_flags( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, fdflags: wasi::__wasi_fdflags_t, ) -> WasiResult<()>299 pub(crate) unsafe fn fd_fdstat_set_flags(
300     wasi_ctx: &WasiCtx,
301     _mem: &mut [u8],
302     fd: wasi::__wasi_fd_t,
303     fdflags: wasi::__wasi_fdflags_t,
304 ) -> WasiResult<()> {
305     trace!("fd_fdstat_set_flags(fd={:?}, fdflags={:#x?})", fd, fdflags);
306 
307     let fd = wasi_ctx.get_entry(fd)?.as_descriptor(0, 0)?.as_os_handle();
308 
309     hostcalls_impl::fd_fdstat_set_flags(&fd, fdflags)
310 }
311 
fd_fdstat_set_rights( wasi_ctx: &mut WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, fs_rights_base: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t, ) -> WasiResult<()>312 pub(crate) unsafe fn fd_fdstat_set_rights(
313     wasi_ctx: &mut WasiCtx,
314     _mem: &mut [u8],
315     fd: wasi::__wasi_fd_t,
316     fs_rights_base: wasi::__wasi_rights_t,
317     fs_rights_inheriting: wasi::__wasi_rights_t,
318 ) -> WasiResult<()> {
319     trace!(
320         "fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})",
321         fd,
322         fs_rights_base,
323         fs_rights_inheriting
324     );
325 
326     let fe = wasi_ctx.get_entry_mut(fd)?;
327     if fe.rights_base & fs_rights_base != fs_rights_base
328         || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting
329     {
330         return Err(WasiError::ENOTCAPABLE);
331     }
332     fe.rights_base = fs_rights_base;
333     fe.rights_inheriting = fs_rights_inheriting;
334 
335     Ok(())
336 }
337 
fd_sync( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, ) -> WasiResult<()>338 pub(crate) unsafe fn fd_sync(
339     wasi_ctx: &WasiCtx,
340     _mem: &mut [u8],
341     fd: wasi::__wasi_fd_t,
342 ) -> WasiResult<()> {
343     trace!("fd_sync(fd={:?})", fd);
344 
345     let fd = wasi_ctx
346         .get_entry(fd)?
347         .as_descriptor(wasi::__WASI_RIGHTS_FD_SYNC, 0)?
348         .as_file()?;
349     fd.sync_all().map_err(Into::into)
350 }
351 
fd_write( wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, iovs_ptr: wasi32::uintptr_t, iovs_len: wasi32::size_t, nwritten: wasi32::uintptr_t, ) -> WasiResult<()>352 pub(crate) unsafe fn fd_write(
353     wasi_ctx: &mut WasiCtx,
354     memory: &mut [u8],
355     fd: wasi::__wasi_fd_t,
356     iovs_ptr: wasi32::uintptr_t,
357     iovs_len: wasi32::size_t,
358     nwritten: wasi32::uintptr_t,
359 ) -> WasiResult<()> {
360     trace!(
361         "fd_write(fd={:?}, iovs_ptr={:#x?}, iovs_len={:?}, nwritten={:#x?})",
362         fd,
363         iovs_ptr,
364         iovs_len,
365         nwritten
366     );
367 
368     let iovs = dec_ciovec_slice(memory, iovs_ptr, iovs_len)?;
369     let iovs: Vec<io::IoSlice> = iovs.iter().map(|vec| host::ciovec_to_host(vec)).collect();
370 
371     // perform unbuffered writes
372     let entry = wasi_ctx.get_entry_mut(fd)?;
373     let isatty = entry.isatty();
374     let desc = entry.as_descriptor_mut(wasi::__WASI_RIGHTS_FD_WRITE, 0)?;
375     let host_nwritten = match desc {
376         Descriptor::OsHandle(file) => {
377             if isatty {
378                 SandboxedTTYWriter::new(file.deref_mut()).write_vectored(&iovs)?
379             } else {
380                 file.write_vectored(&iovs)?
381             }
382         }
383         Descriptor::Stdin => return Err(WasiError::EBADF),
384         Descriptor::Stdout => {
385             // lock for the duration of the scope
386             let stdout = io::stdout();
387             let mut stdout = stdout.lock();
388             let nwritten = if isatty {
389                 SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?
390             } else {
391                 stdout.write_vectored(&iovs)?
392             };
393             stdout.flush()?;
394             nwritten
395         }
396         // Always sanitize stderr, even if it's not directly connected to a tty,
397         // because stderr is meant for diagnostics rather than binary output,
398         // and may be redirected to a file which could end up being displayed
399         // on a tty later.
400         Descriptor::Stderr => SandboxedTTYWriter::new(&mut io::stderr()).write_vectored(&iovs)?,
401     };
402 
403     trace!("     | *nwritten={:?}", host_nwritten);
404 
405     enc_usize_byref(memory, nwritten, host_nwritten)
406 }
407 
fd_advise( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, offset: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t, advice: wasi::__wasi_advice_t, ) -> WasiResult<()>408 pub(crate) unsafe fn fd_advise(
409     wasi_ctx: &WasiCtx,
410     _mem: &mut [u8],
411     fd: wasi::__wasi_fd_t,
412     offset: wasi::__wasi_filesize_t,
413     len: wasi::__wasi_filesize_t,
414     advice: wasi::__wasi_advice_t,
415 ) -> WasiResult<()> {
416     trace!(
417         "fd_advise(fd={:?}, offset={}, len={}, advice={:?})",
418         fd,
419         offset,
420         len,
421         advice
422     );
423 
424     let fd = wasi_ctx
425         .get_entry(fd)?
426         .as_descriptor(wasi::__WASI_RIGHTS_FD_ADVISE, 0)?
427         .as_file()?;
428 
429     hostcalls_impl::fd_advise(fd, advice, offset, len)
430 }
431 
fd_allocate( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, offset: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t, ) -> WasiResult<()>432 pub(crate) unsafe fn fd_allocate(
433     wasi_ctx: &WasiCtx,
434     _mem: &mut [u8],
435     fd: wasi::__wasi_fd_t,
436     offset: wasi::__wasi_filesize_t,
437     len: wasi::__wasi_filesize_t,
438 ) -> WasiResult<()> {
439     trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len);
440 
441     let fd = wasi_ctx
442         .get_entry(fd)?
443         .as_descriptor(wasi::__WASI_RIGHTS_FD_ALLOCATE, 0)?
444         .as_file()?;
445 
446     let metadata = fd.metadata()?;
447 
448     let current_size = metadata.len();
449     let wanted_size = offset.checked_add(len).ok_or(WasiError::E2BIG)?;
450     // This check will be unnecessary when rust-lang/rust#63326 is fixed
451     if wanted_size > i64::max_value() as u64 {
452         return Err(WasiError::E2BIG);
453     }
454 
455     if wanted_size > current_size {
456         fd.set_len(wanted_size).map_err(Into::into)
457     } else {
458         Ok(())
459     }
460 }
461 
path_create_directory( wasi_ctx: &WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, ) -> WasiResult<()>462 pub(crate) unsafe fn path_create_directory(
463     wasi_ctx: &WasiCtx,
464     memory: &mut [u8],
465     dirfd: wasi::__wasi_fd_t,
466     path_ptr: wasi32::uintptr_t,
467     path_len: wasi32::size_t,
468 ) -> WasiResult<()> {
469     trace!(
470         "path_create_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})",
471         dirfd,
472         path_ptr,
473         path_len,
474     );
475 
476     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(helpers::path_from_slice)?;
477 
478     trace!("     | (path_ptr,path_len)='{}'", path);
479 
480     let rights = wasi::__WASI_RIGHTS_PATH_OPEN | wasi::__WASI_RIGHTS_PATH_CREATE_DIRECTORY;
481     let fe = wasi_ctx.get_entry(dirfd)?;
482     let resolved = path_get(fe, rights, 0, 0, path, false)?;
483 
484     hostcalls_impl::path_create_directory(resolved)
485 }
486 
path_link( wasi_ctx: &WasiCtx, memory: &mut [u8], old_dirfd: wasi::__wasi_fd_t, old_flags: wasi::__wasi_lookupflags_t, old_path_ptr: wasi32::uintptr_t, old_path_len: wasi32::size_t, new_dirfd: wasi::__wasi_fd_t, new_path_ptr: wasi32::uintptr_t, new_path_len: wasi32::size_t, ) -> WasiResult<()>487 pub(crate) unsafe fn path_link(
488     wasi_ctx: &WasiCtx,
489     memory: &mut [u8],
490     old_dirfd: wasi::__wasi_fd_t,
491     old_flags: wasi::__wasi_lookupflags_t,
492     old_path_ptr: wasi32::uintptr_t,
493     old_path_len: wasi32::size_t,
494     new_dirfd: wasi::__wasi_fd_t,
495     new_path_ptr: wasi32::uintptr_t,
496     new_path_len: wasi32::size_t,
497 ) -> WasiResult<()> {
498     trace!(
499         "path_link(old_dirfd={:?}, old_flags={:?}, old_path_ptr={:#x?}, old_path_len={}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})",
500         old_dirfd,
501         old_flags,
502         old_path_ptr,
503         old_path_len,
504         new_dirfd,
505         new_path_ptr,
506         new_path_len,
507     );
508 
509     let old_path = dec_slice_of_u8(memory, old_path_ptr, old_path_len).and_then(path_from_slice)?;
510     let new_path = dec_slice_of_u8(memory, new_path_ptr, new_path_len).and_then(path_from_slice)?;
511 
512     trace!("     | (old_path_ptr,old_path_len)='{}'", old_path);
513     trace!("     | (new_path_ptr,new_path_len)='{}'", new_path);
514 
515     let old_fe = wasi_ctx.get_entry(old_dirfd)?;
516     let new_fe = wasi_ctx.get_entry(new_dirfd)?;
517     let resolved_old = path_get(
518         old_fe,
519         wasi::__WASI_RIGHTS_PATH_LINK_SOURCE,
520         0,
521         0,
522         old_path,
523         false,
524     )?;
525     let resolved_new = path_get(
526         new_fe,
527         wasi::__WASI_RIGHTS_PATH_LINK_TARGET,
528         0,
529         0,
530         new_path,
531         false,
532     )?;
533 
534     hostcalls_impl::path_link(resolved_old, resolved_new)
535 }
536 
path_open( wasi_ctx: &mut WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, dirflags: wasi::__wasi_lookupflags_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, oflags: wasi::__wasi_oflags_t, fs_rights_base: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t, fs_flags: wasi::__wasi_fdflags_t, fd_out_ptr: wasi32::uintptr_t, ) -> WasiResult<()>537 pub(crate) unsafe fn path_open(
538     wasi_ctx: &mut WasiCtx,
539     memory: &mut [u8],
540     dirfd: wasi::__wasi_fd_t,
541     dirflags: wasi::__wasi_lookupflags_t,
542     path_ptr: wasi32::uintptr_t,
543     path_len: wasi32::size_t,
544     oflags: wasi::__wasi_oflags_t,
545     fs_rights_base: wasi::__wasi_rights_t,
546     fs_rights_inheriting: wasi::__wasi_rights_t,
547     fs_flags: wasi::__wasi_fdflags_t,
548     fd_out_ptr: wasi32::uintptr_t,
549 ) -> WasiResult<()> {
550     trace!(
551         "path_open(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd_out_ptr={:#x?})",
552         dirfd,
553         dirflags,
554         path_ptr,
555         path_len,
556         oflags,
557         fs_rights_base,
558         fs_rights_inheriting,
559         fs_flags,
560         fd_out_ptr
561     );
562 
563     // pre-encode fd_out_ptr to -1 in case of error in opening a path
564     enc_fd_byref(memory, fd_out_ptr, wasi::__wasi_fd_t::max_value())?;
565 
566     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(path_from_slice)?;
567 
568     trace!("     | (path_ptr,path_len)='{}'", path);
569 
570     let (needed_base, needed_inheriting) =
571         path_open_rights(fs_rights_base, fs_rights_inheriting, oflags, fs_flags);
572     let fe = wasi_ctx.get_entry(dirfd)?;
573     let resolved = path_get(
574         fe,
575         needed_base,
576         needed_inheriting,
577         dirflags,
578         path,
579         oflags & wasi::__WASI_OFLAGS_CREAT != 0,
580     )?;
581 
582     // which open mode do we need?
583     let read = fs_rights_base & (wasi::__WASI_RIGHTS_FD_READ | wasi::__WASI_RIGHTS_FD_READDIR) != 0;
584     let write = fs_rights_base
585         & (wasi::__WASI_RIGHTS_FD_DATASYNC
586             | wasi::__WASI_RIGHTS_FD_WRITE
587             | wasi::__WASI_RIGHTS_FD_ALLOCATE
588             | wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE)
589         != 0;
590 
591     let fd = hostcalls_impl::path_open(resolved, read, write, oflags, fs_flags)?;
592 
593     // Determine the type of the new file descriptor and which rights contradict with this type
594     let (_ty, max_base, max_inheriting) = determine_type_rights(&fd)?;
595     let mut fe = Entry::from(fd)?;
596     fe.rights_base &= max_base;
597     fe.rights_inheriting &= max_inheriting;
598     let guest_fd = wasi_ctx.insert_entry(fe)?;
599 
600     trace!("     | *fd={:?}", guest_fd);
601 
602     enc_fd_byref(memory, fd_out_ptr, guest_fd)
603 }
604 
path_readlink( wasi_ctx: &WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, buf_ptr: wasi32::uintptr_t, buf_len: wasi32::size_t, buf_used: wasi32::uintptr_t, ) -> WasiResult<()>605 pub(crate) unsafe fn path_readlink(
606     wasi_ctx: &WasiCtx,
607     memory: &mut [u8],
608     dirfd: wasi::__wasi_fd_t,
609     path_ptr: wasi32::uintptr_t,
610     path_len: wasi32::size_t,
611     buf_ptr: wasi32::uintptr_t,
612     buf_len: wasi32::size_t,
613     buf_used: wasi32::uintptr_t,
614 ) -> WasiResult<()> {
615     trace!(
616         "path_readlink(dirfd={:?}, path_ptr={:#x?}, path_len={:?}, buf_ptr={:#x?}, buf_len={}, buf_used={:#x?})",
617         dirfd,
618         path_ptr,
619         path_len,
620         buf_ptr,
621         buf_len,
622         buf_used,
623     );
624 
625     enc_usize_byref(memory, buf_used, 0)?;
626 
627     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(helpers::path_from_slice)?;
628 
629     trace!("     | (path_ptr,path_len)='{}'", &path);
630 
631     let fe = wasi_ctx.get_entry(dirfd)?;
632     let resolved = path_get(fe, wasi::__WASI_RIGHTS_PATH_READLINK, 0, 0, &path, false)?;
633 
634     let mut buf = dec_slice_of_mut_u8(memory, buf_ptr, buf_len)?;
635 
636     let host_bufused = hostcalls_impl::path_readlink(resolved, &mut buf)?;
637 
638     trace!("     | (buf_ptr,*buf_used)={:?}", buf);
639     trace!("     | *buf_used={:?}", host_bufused);
640 
641     enc_usize_byref(memory, buf_used, host_bufused)
642 }
643 
path_rename( wasi_ctx: &WasiCtx, memory: &mut [u8], old_dirfd: wasi::__wasi_fd_t, old_path_ptr: wasi32::uintptr_t, old_path_len: wasi32::size_t, new_dirfd: wasi::__wasi_fd_t, new_path_ptr: wasi32::uintptr_t, new_path_len: wasi32::size_t, ) -> WasiResult<()>644 pub(crate) unsafe fn path_rename(
645     wasi_ctx: &WasiCtx,
646     memory: &mut [u8],
647     old_dirfd: wasi::__wasi_fd_t,
648     old_path_ptr: wasi32::uintptr_t,
649     old_path_len: wasi32::size_t,
650     new_dirfd: wasi::__wasi_fd_t,
651     new_path_ptr: wasi32::uintptr_t,
652     new_path_len: wasi32::size_t,
653 ) -> WasiResult<()> {
654     trace!(
655         "path_rename(old_dirfd={:?}, old_path_ptr={:#x?}, old_path_len={:?}, new_dirfd={:?}, new_path_ptr={:#x?}, new_path_len={:?})",
656         old_dirfd,
657         old_path_ptr,
658         old_path_len,
659         new_dirfd,
660         new_path_ptr,
661         new_path_len,
662     );
663 
664     let old_path = dec_slice_of_u8(memory, old_path_ptr, old_path_len).and_then(path_from_slice)?;
665     let new_path = dec_slice_of_u8(memory, new_path_ptr, new_path_len).and_then(path_from_slice)?;
666 
667     trace!("     | (old_path_ptr,old_path_len)='{}'", old_path);
668     trace!("     | (new_path_ptr,new_path_len)='{}'", new_path);
669 
670     let old_fe = wasi_ctx.get_entry(old_dirfd)?;
671     let new_fe = wasi_ctx.get_entry(new_dirfd)?;
672     let resolved_old = path_get(
673         old_fe,
674         wasi::__WASI_RIGHTS_PATH_RENAME_SOURCE,
675         0,
676         0,
677         old_path,
678         true,
679     )?;
680     let resolved_new = path_get(
681         new_fe,
682         wasi::__WASI_RIGHTS_PATH_RENAME_TARGET,
683         0,
684         0,
685         new_path,
686         true,
687     )?;
688 
689     log::debug!("path_rename resolved_old={:?}", resolved_old);
690     log::debug!("path_rename resolved_new={:?}", resolved_new);
691 
692     hostcalls_impl::path_rename(resolved_old, resolved_new)
693 }
694 
fd_filestat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, filestat_ptr: wasi32::uintptr_t, ) -> WasiResult<()>695 pub(crate) unsafe fn fd_filestat_get(
696     wasi_ctx: &WasiCtx,
697     memory: &mut [u8],
698     fd: wasi::__wasi_fd_t,
699     filestat_ptr: wasi32::uintptr_t,
700 ) -> WasiResult<()> {
701     trace!(
702         "fd_filestat_get(fd={:?}, filestat_ptr={:#x?})",
703         fd,
704         filestat_ptr
705     );
706 
707     let fd = wasi_ctx.get_entry(fd)?.as_descriptor(0, 0)?.as_file()?;
708     let host_filestat = hostcalls_impl::fd_filestat_get(fd)?;
709 
710     trace!("     | *filestat_ptr={:?}", host_filestat);
711 
712     enc_filestat_byref(memory, filestat_ptr, host_filestat)
713 }
714 
fd_filestat_set_times( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, st_atim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t, fst_flags: wasi::__wasi_fstflags_t, ) -> WasiResult<()>715 pub(crate) unsafe fn fd_filestat_set_times(
716     wasi_ctx: &WasiCtx,
717     _mem: &mut [u8],
718     fd: wasi::__wasi_fd_t,
719     st_atim: wasi::__wasi_timestamp_t,
720     st_mtim: wasi::__wasi_timestamp_t,
721     fst_flags: wasi::__wasi_fstflags_t,
722 ) -> WasiResult<()> {
723     trace!(
724         "fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fst_flags={:#x?})",
725         fd,
726         st_atim,
727         st_mtim,
728         fst_flags
729     );
730 
731     let fd = wasi_ctx
732         .get_entry(fd)?
733         .as_descriptor(wasi::__WASI_RIGHTS_FD_FILESTAT_SET_TIMES, 0)?
734         .as_file()?;
735 
736     fd_filestat_set_times_impl(fd, st_atim, st_mtim, fst_flags)
737 }
738 
fd_filestat_set_times_impl( fd: &File, st_atim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t, fst_flags: wasi::__wasi_fstflags_t, ) -> WasiResult<()>739 pub(crate) fn fd_filestat_set_times_impl(
740     fd: &File,
741     st_atim: wasi::__wasi_timestamp_t,
742     st_mtim: wasi::__wasi_timestamp_t,
743     fst_flags: wasi::__wasi_fstflags_t,
744 ) -> WasiResult<()> {
745     let set_atim = fst_flags & wasi::__WASI_FSTFLAGS_ATIM != 0;
746     let set_atim_now = fst_flags & wasi::__WASI_FSTFLAGS_ATIM_NOW != 0;
747     let set_mtim = fst_flags & wasi::__WASI_FSTFLAGS_MTIM != 0;
748     let set_mtim_now = fst_flags & wasi::__WASI_FSTFLAGS_MTIM_NOW != 0;
749 
750     if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
751         return Err(WasiError::EINVAL);
752     }
753     let atim = if set_atim {
754         let time = UNIX_EPOCH + Duration::from_nanos(st_atim);
755         Some(FileTime::from_system_time(time))
756     } else if set_atim_now {
757         let time = SystemTime::now();
758         Some(FileTime::from_system_time(time))
759     } else {
760         None
761     };
762 
763     let mtim = if set_mtim {
764         let time = UNIX_EPOCH + Duration::from_nanos(st_mtim);
765         Some(FileTime::from_system_time(time))
766     } else if set_mtim_now {
767         let time = SystemTime::now();
768         Some(FileTime::from_system_time(time))
769     } else {
770         None
771     };
772     set_file_handle_times(fd, atim, mtim).map_err(Into::into)
773 }
774 
fd_filestat_set_size( wasi_ctx: &WasiCtx, _mem: &mut [u8], fd: wasi::__wasi_fd_t, st_size: wasi::__wasi_filesize_t, ) -> WasiResult<()>775 pub(crate) unsafe fn fd_filestat_set_size(
776     wasi_ctx: &WasiCtx,
777     _mem: &mut [u8],
778     fd: wasi::__wasi_fd_t,
779     st_size: wasi::__wasi_filesize_t,
780 ) -> WasiResult<()> {
781     trace!("fd_filestat_set_size(fd={:?}, st_size={})", fd, st_size);
782 
783     let fd = wasi_ctx
784         .get_entry(fd)?
785         .as_descriptor(wasi::__WASI_RIGHTS_FD_FILESTAT_SET_SIZE, 0)?
786         .as_file()?;
787 
788     // This check will be unnecessary when rust-lang/rust#63326 is fixed
789     if st_size > i64::max_value() as u64 {
790         return Err(WasiError::E2BIG);
791     }
792     fd.set_len(st_size).map_err(Into::into)
793 }
794 
path_filestat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, dirflags: wasi::__wasi_lookupflags_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, filestat_ptr: wasi32::uintptr_t, ) -> WasiResult<()>795 pub(crate) unsafe fn path_filestat_get(
796     wasi_ctx: &WasiCtx,
797     memory: &mut [u8],
798     dirfd: wasi::__wasi_fd_t,
799     dirflags: wasi::__wasi_lookupflags_t,
800     path_ptr: wasi32::uintptr_t,
801     path_len: wasi32::size_t,
802     filestat_ptr: wasi32::uintptr_t,
803 ) -> WasiResult<()> {
804     trace!(
805         "path_filestat_get(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, filestat_ptr={:#x?})",
806         dirfd,
807         dirflags,
808         path_ptr,
809         path_len,
810         filestat_ptr
811     );
812 
813     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(path_from_slice)?;
814 
815     trace!("     | (path_ptr,path_len)='{}'", path);
816 
817     let fe = wasi_ctx.get_entry(dirfd)?;
818     let resolved = path_get(
819         fe,
820         wasi::__WASI_RIGHTS_PATH_FILESTAT_GET,
821         0,
822         dirflags,
823         path,
824         false,
825     )?;
826     let host_filestat = hostcalls_impl::path_filestat_get(resolved, dirflags)?;
827 
828     trace!("     | *filestat_ptr={:?}", host_filestat);
829 
830     enc_filestat_byref(memory, filestat_ptr, host_filestat)
831 }
832 
path_filestat_set_times( wasi_ctx: &WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, dirflags: wasi::__wasi_lookupflags_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, st_atim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t, fst_flags: wasi::__wasi_fstflags_t, ) -> WasiResult<()>833 pub(crate) unsafe fn path_filestat_set_times(
834     wasi_ctx: &WasiCtx,
835     memory: &mut [u8],
836     dirfd: wasi::__wasi_fd_t,
837     dirflags: wasi::__wasi_lookupflags_t,
838     path_ptr: wasi32::uintptr_t,
839     path_len: wasi32::size_t,
840     st_atim: wasi::__wasi_timestamp_t,
841     st_mtim: wasi::__wasi_timestamp_t,
842     fst_flags: wasi::__wasi_fstflags_t,
843 ) -> WasiResult<()> {
844     trace!(
845         "path_filestat_set_times(dirfd={:?}, dirflags={:?}, path_ptr={:#x?}, path_len={}, st_atim={}, st_mtim={}, fst_flags={:#x?})",
846         dirfd,
847         dirflags,
848         path_ptr,
849         path_len,
850         st_atim, st_mtim,
851         fst_flags
852     );
853 
854     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(path_from_slice)?;
855 
856     trace!("     | (path_ptr,path_len)='{}'", path);
857 
858     let fe = wasi_ctx.get_entry(dirfd)?;
859     let resolved = path_get(
860         fe,
861         wasi::__WASI_RIGHTS_PATH_FILESTAT_SET_TIMES,
862         0,
863         dirflags,
864         path,
865         false,
866     )?;
867 
868     hostcalls_impl::path_filestat_set_times(resolved, dirflags, st_atim, st_mtim, fst_flags)
869 }
870 
path_symlink( wasi_ctx: &WasiCtx, memory: &mut [u8], old_path_ptr: wasi32::uintptr_t, old_path_len: wasi32::size_t, dirfd: wasi::__wasi_fd_t, new_path_ptr: wasi32::uintptr_t, new_path_len: wasi32::size_t, ) -> WasiResult<()>871 pub(crate) unsafe fn path_symlink(
872     wasi_ctx: &WasiCtx,
873     memory: &mut [u8],
874     old_path_ptr: wasi32::uintptr_t,
875     old_path_len: wasi32::size_t,
876     dirfd: wasi::__wasi_fd_t,
877     new_path_ptr: wasi32::uintptr_t,
878     new_path_len: wasi32::size_t,
879 ) -> WasiResult<()> {
880     trace!(
881         "path_symlink(old_path_ptr={:#x?}, old_path_len={}, dirfd={:?}, new_path_ptr={:#x?}, new_path_len={})",
882         old_path_ptr,
883         old_path_len,
884         dirfd,
885         new_path_ptr,
886         new_path_len
887     );
888 
889     let old_path = dec_slice_of_u8(memory, old_path_ptr, old_path_len).and_then(path_from_slice)?;
890     let new_path = dec_slice_of_u8(memory, new_path_ptr, new_path_len).and_then(path_from_slice)?;
891 
892     trace!("     | (old_path_ptr,old_path_len)='{}'", old_path);
893     trace!("     | (new_path_ptr,new_path_len)='{}'", new_path);
894 
895     let fe = wasi_ctx.get_entry(dirfd)?;
896     let resolved_new = path_get(fe, wasi::__WASI_RIGHTS_PATH_SYMLINK, 0, 0, new_path, true)?;
897 
898     hostcalls_impl::path_symlink(old_path, resolved_new)
899 }
900 
path_unlink_file( wasi_ctx: &WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, ) -> WasiResult<()>901 pub(crate) unsafe fn path_unlink_file(
902     wasi_ctx: &WasiCtx,
903     memory: &mut [u8],
904     dirfd: wasi::__wasi_fd_t,
905     path_ptr: wasi32::uintptr_t,
906     path_len: wasi32::size_t,
907 ) -> WasiResult<()> {
908     trace!(
909         "path_unlink_file(dirfd={:?}, path_ptr={:#x?}, path_len={})",
910         dirfd,
911         path_ptr,
912         path_len
913     );
914 
915     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(path_from_slice)?;
916 
917     trace!("     | (path_ptr,path_len)='{}'", path);
918 
919     let fe = wasi_ctx.get_entry(dirfd)?;
920     let resolved = path_get(fe, wasi::__WASI_RIGHTS_PATH_UNLINK_FILE, 0, 0, path, false)?;
921 
922     hostcalls_impl::path_unlink_file(resolved)
923 }
924 
path_remove_directory( wasi_ctx: &WasiCtx, memory: &mut [u8], dirfd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, ) -> WasiResult<()>925 pub(crate) unsafe fn path_remove_directory(
926     wasi_ctx: &WasiCtx,
927     memory: &mut [u8],
928     dirfd: wasi::__wasi_fd_t,
929     path_ptr: wasi32::uintptr_t,
930     path_len: wasi32::size_t,
931 ) -> WasiResult<()> {
932     trace!(
933         "path_remove_directory(dirfd={:?}, path_ptr={:#x?}, path_len={})",
934         dirfd,
935         path_ptr,
936         path_len
937     );
938 
939     let path = dec_slice_of_u8(memory, path_ptr, path_len).and_then(path_from_slice)?;
940 
941     trace!("     | (path_ptr,path_len)='{}'", path);
942 
943     let fe = wasi_ctx.get_entry(dirfd)?;
944     let resolved = path_get(
945         fe,
946         wasi::__WASI_RIGHTS_PATH_REMOVE_DIRECTORY,
947         0,
948         0,
949         path,
950         true,
951     )?;
952 
953     log::debug!("path_remove_directory resolved={:?}", resolved);
954 
955     hostcalls_impl::path_remove_directory(resolved)
956 }
957 
fd_prestat_get( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, prestat_ptr: wasi32::uintptr_t, ) -> WasiResult<()>958 pub(crate) unsafe fn fd_prestat_get(
959     wasi_ctx: &WasiCtx,
960     memory: &mut [u8],
961     fd: wasi::__wasi_fd_t,
962     prestat_ptr: wasi32::uintptr_t,
963 ) -> WasiResult<()> {
964     trace!(
965         "fd_prestat_get(fd={:?}, prestat_ptr={:#x?})",
966         fd,
967         prestat_ptr
968     );
969 
970     // TODO: should we validate any rights here?
971     let fe = wasi_ctx.get_entry(fd)?;
972     let po_path = fe.preopen_path.as_ref().ok_or(WasiError::ENOTSUP)?;
973     if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
974         return Err(WasiError::ENOTDIR);
975     }
976 
977     let path = host_impl::path_from_host(po_path.as_os_str())?;
978 
979     enc_prestat_byref(
980         memory,
981         prestat_ptr,
982         host::__wasi_prestat_t {
983             tag: wasi::__WASI_PREOPENTYPE_DIR,
984             u: host::__wasi_prestat_u_t {
985                 dir: host::__wasi_prestat_dir_t {
986                     pr_name_len: path.len(),
987                 },
988             },
989         },
990     )
991 }
992 
fd_prestat_dir_name( wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, path_ptr: wasi32::uintptr_t, path_len: wasi32::size_t, ) -> WasiResult<()>993 pub(crate) unsafe fn fd_prestat_dir_name(
994     wasi_ctx: &WasiCtx,
995     memory: &mut [u8],
996     fd: wasi::__wasi_fd_t,
997     path_ptr: wasi32::uintptr_t,
998     path_len: wasi32::size_t,
999 ) -> WasiResult<()> {
1000     trace!(
1001         "fd_prestat_dir_name(fd={:?}, path_ptr={:#x?}, path_len={})",
1002         fd,
1003         path_ptr,
1004         path_len
1005     );
1006 
1007     // TODO: should we validate any rights here?
1008     let fe = wasi_ctx.get_entry(fd)?;
1009     let po_path = fe.preopen_path.as_ref().ok_or(WasiError::ENOTSUP)?;
1010     if fe.file_type != wasi::__WASI_FILETYPE_DIRECTORY {
1011         return Err(WasiError::ENOTDIR);
1012     }
1013 
1014     let path = host_impl::path_from_host(po_path.as_os_str())?;
1015 
1016     if path.len() > dec_usize(path_len) {
1017         return Err(WasiError::ENAMETOOLONG);
1018     }
1019 
1020     trace!("     | (path_ptr,path_len)='{}'", path);
1021 
1022     enc_slice_of_u8(memory, path.as_bytes(), path_ptr)
1023 }
1024 
fd_readdir( wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t, buf: wasi32::uintptr_t, buf_len: wasi32::size_t, cookie: wasi::__wasi_dircookie_t, buf_used: wasi32::uintptr_t, ) -> WasiResult<()>1025 pub(crate) unsafe fn fd_readdir(
1026     wasi_ctx: &mut WasiCtx,
1027     memory: &mut [u8],
1028     fd: wasi::__wasi_fd_t,
1029     buf: wasi32::uintptr_t,
1030     buf_len: wasi32::size_t,
1031     cookie: wasi::__wasi_dircookie_t,
1032     buf_used: wasi32::uintptr_t,
1033 ) -> WasiResult<()> {
1034     trace!(
1035         "fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})",
1036         fd,
1037         buf,
1038         buf_len,
1039         cookie,
1040         buf_used,
1041     );
1042 
1043     enc_usize_byref(memory, buf_used, 0)?;
1044 
1045     let file = wasi_ctx
1046         .get_entry_mut(fd)?
1047         .as_descriptor_mut(wasi::__WASI_RIGHTS_FD_READDIR, 0)?
1048         .as_file_mut()?;
1049     let mut host_buf = dec_slice_of_mut_u8(memory, buf, buf_len)?;
1050 
1051     trace!("     | (buf,buf_len)={:?}", host_buf);
1052 
1053     let iter = hostcalls_impl::fd_readdir(file, cookie)?;
1054     let mut host_bufused = 0;
1055     for dirent in iter {
1056         let dirent_raw = dirent?.to_wasi_raw()?;
1057         let offset = dirent_raw.len();
1058         if host_buf.len() < offset {
1059             break;
1060         } else {
1061             host_buf[0..offset].copy_from_slice(&dirent_raw);
1062             host_bufused += offset;
1063             host_buf = &mut host_buf[offset..];
1064         }
1065     }
1066 
1067     trace!("     | *buf_used={:?}", host_bufused);
1068 
1069     enc_usize_byref(memory, buf_used, host_bufused)
1070 }
1071