diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index e57a8aa4bd..e6f7596c85 100644 --- a/crates/wasi-c2/src/dir.rs +++ b/crates/wasi-c2/src/dir.rs @@ -22,6 +22,7 @@ pub trait WasiDir { fn symlink(&self, old_path: &str, new_path: &str) -> Result<(), Error>; fn remove_dir(&self, path: &str) -> Result<(), Error>; fn unlink_file(&self, path: &str) -> Result<(), Error>; + fn read_link(&self, path: &str) -> Result; } pub(crate) struct DirEntry { @@ -304,4 +305,8 @@ impl WasiDir for cap_std::fs::Dir { self.remove_file(Path::new(path))?; Ok(()) } + fn read_link(&self, path: &str) -> Result { + let link = self.read_link(Path::new(path))?; + Ok(link) + } } diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 24eeb8f542..cee8f4fa8e 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -644,7 +644,23 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { buf: &GuestPtr, buf_len: types::Size, ) -> Result { - unimplemented!() + let table = self.table(); + let dir_entry: Ref = table.get(u32::from(dirfd))?; + let dir = dir_entry.get_cap(DirCaps::READLINK)?; + let path = path.as_str()?; + let link = dir + .read_link(path.deref())? + .into_os_string() + .into_string() + .map_err(|_| Error::Utf8(todo!()))?; + let link_bytes = link.as_bytes(); + let link_len = link_bytes.len(); + if link_len > buf_len as usize { + return Err(Error::Nametoolong); + } + let mut buf = buf.as_array(link_len as u32).as_slice_mut()?; + buf.copy_from_slice(link_bytes); + Ok(link_len as types::Size) } fn path_remove_directory( @@ -666,6 +682,8 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { new_fd: types::Fd, new_path: &GuestPtr<'_, str>, ) -> Result<(), Error> { + // XXX: Dir::rename requires (to_dir: &Self), but in the table we just have a dyn WasiDir. + // The downcast isn't possible. unimplemented!() }