diff --git a/crates/wasi-c2/TEST_FAILURES b/crates/wasi-c2/TEST_FAILURES index d620a4c894..866e4a060f 100644 --- a/crates/wasi-c2/TEST_FAILURES +++ b/crates/wasi-c2/TEST_FAILURES @@ -12,11 +12,8 @@ wasi_tests::path_filestat - fdstat.fs_flags is not populated correctly wasi_tests::path_link - path_link is not implemented -wasi_tests::path_rename - - path_rename is not implemented. we need to be able to downcast a dyn - WasiDir to a concrete Dir for this to be possible - need to reintroduce Any to hierarchy wasi_tests::path_rename_trailing_slashes - - path_rename is not implemented + - unclear, trailing slash behavior is wrong wasi_tests::path_symlink_trailing_slashes - unclear, path_symlink is giving a ENOTDIR when it expects an EEXIST... wasi_tests::poll_oneoff diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index 718f499db9..d70e3c554c 100644 --- a/crates/wasi-c2/src/dir.rs +++ b/crates/wasi-c2/src/dir.rs @@ -1,10 +1,12 @@ use crate::error::Error; use crate::file::{FdFlags, FileCaps, FileType, Filestat, OFlags, WasiFile}; +use std::any::Any; use std::convert::TryInto; use std::ops::Deref; use std::path::{Path, PathBuf}; pub trait WasiDir { + fn as_any(&self) -> &dyn Any; fn open_file( &self, symlink_follow: bool, @@ -24,6 +26,7 @@ pub trait WasiDir { fn unlink_file(&self, path: &str) -> Result<(), Error>; fn read_link(&self, path: &str) -> Result; fn get_filestat(&self) -> Result; + fn rename(&self, path: &str, dest_dir: &dyn WasiDir, dest_path: &str) -> Result<(), Error>; } pub(crate) struct DirEntry { @@ -196,6 +199,9 @@ impl From for u64 { } impl WasiDir for cap_std::fs::Dir { + fn as_any(&self) -> &dyn Any { + self + } fn open_file( &self, symlink_follow: bool, @@ -349,4 +355,12 @@ impl WasiDir for cap_std::fs::Dir { ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None), }) } + fn rename(&self, src_path: &str, dest_dir: &dyn WasiDir, dest_path: &str) -> Result<(), Error> { + let dest_dir = dest_dir + .as_any() + .downcast_ref::() + .ok_or(Error::NotCapable)?; + self.rename(Path::new(src_path), dest_dir, Path::new(dest_path))?; + Ok(()) + } } diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 1013a56377..9bec5adb6c 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -771,14 +771,21 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn path_rename( &self, - old_fd: types::Fd, - old_path: &GuestPtr<'_, str>, - new_fd: types::Fd, - new_path: &GuestPtr<'_, str>, + src_fd: types::Fd, + src_path: &GuestPtr<'_, str>, + dest_fd: types::Fd, + dest_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!() + let table = self.table(); + let src_entry: Ref = table.get(u32::from(src_fd))?; + let src_dir = src_entry.get_cap(DirCaps::RENAME_SOURCE)?; + let dest_entry: Ref = table.get(u32::from(dest_fd))?; + let dest_dir = dest_entry.get_cap(DirCaps::RENAME_TARGET)?; + src_dir.rename( + src_path.as_str()?.deref(), + dest_dir.deref(), + dest_path.as_str()?.deref(), + ) } fn path_symlink(