diff --git a/crates/test-programs/wasi-tests/src/bin/path_link.rs b/crates/test-programs/wasi-tests/src/bin/path_link.rs index 3e005012fd..eff44662fd 100644 --- a/crates/test-programs/wasi-tests/src/bin/path_link.rs +++ b/crates/test-programs/wasi-tests/src/bin/path_link.rs @@ -152,26 +152,19 @@ unsafe fn test_path_link(dir_fd: wasi::Fd) { // Create a link to a dangling symlink wasi::path_symlink("target", dir_fd, "symlink").expect("creating a dangling symlink"); - assert_eq!( - wasi::path_link(dir_fd, 0, "symlink", dir_fd, "link") - .expect_err("creating a link to a dangling symlink should fail") - .raw_error(), - wasi::ERRNO_NOENT, - "errno should be ERRNO_NOENT" - ); + // This should succeed, because we're not following symlinks + wasi::path_link(dir_fd, 0, "symlink", dir_fd, "link") + .expect("creating a link to a dangling symlink should succeed"); wasi::path_unlink_file(dir_fd, "symlink").expect("removing a symlink"); + wasi::path_unlink_file(dir_fd, "link").expect("removing a hardlink"); // Create a link to a symlink loop wasi::path_symlink("symlink", dir_fd, "symlink").expect("creating a symlink loop"); - assert_eq!( - wasi::path_link(dir_fd, 0, "symlink", dir_fd, "link") - .expect_err("creating a link to a symlink loop") - .raw_error(), - wasi::ERRNO_LOOP, - "errno should be ERRNO_LOOP" - ); + wasi::path_link(dir_fd, 0, "symlink", dir_fd, "link") + .expect("creating a link to a symlink loop should succeed"); wasi::path_unlink_file(dir_fd, "symlink").expect("removing a symlink"); + wasi::path_unlink_file(dir_fd, "link").expect("removing a hardlink"); // Create a link where target is a dangling symlink wasi::path_symlink("target", dir_fd, "symlink").expect("creating a dangling symlink"); @@ -203,6 +196,7 @@ unsafe fn test_path_link(dir_fd: wasi::Fd) { // Create a link where target is a dangling symlink following symlinks wasi::path_symlink("target", dir_fd, "symlink").expect("creating a dangling symlink"); + // If we do follow symlinks, this should fail assert_eq!( wasi::path_link( dir_fd, @@ -211,7 +205,7 @@ unsafe fn test_path_link(dir_fd: wasi::Fd) { dir_fd, "link", ) - .expect_err("creating a link where target is a dangling symlink following symlinks") + .expect_err("creating a link to a dangling symlink following symlinks should fail") .raw_error(), wasi::ERRNO_NOENT, "errno should be ERRNO_NOENT" diff --git a/crates/wasi-common/src/hostcalls_impl/fs.rs b/crates/wasi-common/src/hostcalls_impl/fs.rs index ecedc67b71..614d21a5a7 100644 --- a/crates/wasi-common/src/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/hostcalls_impl/fs.rs @@ -650,7 +650,9 @@ pub(crate) unsafe fn path_link( false, )?; - hostcalls_impl::path_link(resolved_old, resolved_new) + let follow_symlinks = old_flags & wasi::__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW != 0; + + hostcalls_impl::path_link(resolved_old, resolved_new, follow_symlinks) } pub(crate) unsafe fn path_open( diff --git a/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs b/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs index 63eb64fdc0..08507ec2ea 100644 --- a/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs @@ -71,15 +71,24 @@ pub(crate) fn path_create_directory(base: &File, path: &str) -> WasiResult<()> { unsafe { mkdirat(base.as_raw_fd(), path, Mode::from_bits_truncate(0o777)) }.map_err(Into::into) } -pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> { +pub(crate) fn path_link( + resolved_old: PathGet, + resolved_new: PathGet, + follow_symlinks: bool, +) -> WasiResult<()> { use yanix::file::{linkat, AtFlag}; + let flags = if follow_symlinks { + AtFlag::SYMLINK_FOLLOW + } else { + AtFlag::empty() + }; unsafe { linkat( resolved_old.dirfd().as_raw_fd(), resolved_old.path(), resolved_new.dirfd().as_raw_fd(), resolved_new.path(), - AtFlag::SYMLINK_FOLLOW, + flags, ) } .map_err(Into::into) diff --git a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs index 1f91e6f9a9..929ea1a177 100644 --- a/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/sys/windows/hostcalls_impl/fs.rs @@ -129,7 +129,11 @@ pub(crate) fn path_create_directory(file: &File, path: &str) -> WasiResult<()> { std::fs::create_dir(&path).map_err(Into::into) } -pub(crate) fn path_link(resolved_old: PathGet, resolved_new: PathGet) -> WasiResult<()> { +pub(crate) fn path_link( + resolved_old: PathGet, + resolved_new: PathGet, + follow_symlinks: bool, +) -> WasiResult<()> { unimplemented!("path_link") }