diff --git a/lib/runtime-core/src/memory/ptr.rs b/lib/runtime-core/src/memory/ptr.rs index 465474c13..0a9454acc 100644 --- a/lib/runtime-core/src/memory/ptr.rs +++ b/lib/runtime-core/src/memory/ptr.rs @@ -126,6 +126,15 @@ impl WasmPtr { [index as usize..slice_full_len]; Some(cell_ptrs) } + + pub fn get_utf8_string<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> { + if self.offset as usize + str_len as usize > memory.size().bytes().0 { + return None; + } + let ptr = unsafe { memory.view::().as_ptr().add(self.offset as usize) as *const u8 }; + let slice: &[u8] = unsafe { std::slice::from_raw_parts(ptr, str_len as usize) }; + std::str::from_utf8(slice).ok() + } } unsafe impl WasmExternType for WasmPtr { diff --git a/lib/wasi/src/ptr.rs b/lib/wasi/src/ptr.rs index 0af012eac..87bdc104c 100644 --- a/lib/wasi/src/ptr.rs +++ b/lib/wasi/src/ptr.rs @@ -75,4 +75,9 @@ impl WasmPtr { ) -> Result<&'a [Cell], __wasi_errno_t> { self.0.deref(memory, index, length).ok_or(__WASI_EFAULT) } + + #[inline(always)] + pub fn get_utf8_string<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> { + self.0.get_utf8_string(memory, str_len) + } } diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 452532627..ac2354fc4 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -1608,7 +1608,29 @@ pub fn path_readlink( buf_used: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::path_readlink"); - unimplemented!("wasi::path_readlink") + let state = get_wasi_state(ctx); + let memory = ctx.memory(0); + + let base_dir = wasi_try!(state.fs.fd_map.get(&dir_fd).ok_or(__WASI_EBADF)); + let path_str = wasi_try!(path.get_utf8_string(memory, path_len).ok_or(__WASI_EINVAL)); + let result = wasi_try!(std::fs::read_link(path_str).ok().ok_or(__WASI_EIO)); + let result_path_as_str = result.to_string_lossy(); + let bytes = result_path_as_str.bytes(); + if bytes.len() < buf_len as usize { + return __WASI_EOVERFLOW; + } + + let out = wasi_try!(buf.deref(memory, 0, buf_len)); + let mut bytes_written = 0; + for b in bytes { + out[bytes_written].set(b); + bytes_written += 1; + } + + let bytes_out = wasi_try!(buf_used.deref(memory)); + bytes_out.set(bytes_written as u32); + + __WASI_ESUCCESS } pub fn path_remove_directory(