From 35b442fd4c3171f646be1b03e92ec0cf14d53d74 Mon Sep 17 00:00:00 2001 From: Anthony DePasquale Date: Mon, 30 Mar 2026 16:56:05 +0200 Subject: [PATCH 1/3] ln: add WASI support via symlink_path On wasm32-wasip1, std::os::unix::fs::symlink is not available, but WASI preview 1 provides path_symlink which Rust exposes as std::os::wasi::fs::symlink_path. Import it under the symlink alias so the existing call site works without changes. Follows the same pattern as cp.rs for enabling wasi_ext. --- src/uu/ln/src/ln.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 5fb75a86730..7556fb2b6e0 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -3,6 +3,8 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] + // spell-checker:ignore (ToDO) srcpath targetpath EEXIST use clap::{Arg, ArgAction, Command}; @@ -21,6 +23,8 @@ use thiserror::Error; #[cfg(any(unix, target_os = "redox"))] use std::os::unix::fs::symlink; +#[cfg(target_os = "wasi")] +use std::os::wasi::fs::symlink_path as symlink; #[cfg(windows)] use std::os::windows::fs::{symlink_dir, symlink_file}; use std::path::{Path, PathBuf}; @@ -488,11 +492,3 @@ pub fn symlink, P2: AsRef>(src: P1, dst: P2) -> std::io::R symlink_file(src, dst) } } - -#[cfg(target_os = "wasi")] -fn symlink, P2: AsRef>(_src: P1, _dst: P2) -> std::io::Result<()> { - Err(std::io::Error::new( - std::io::ErrorKind::Unsupported, - "symlinks not supported on this platform", - )) -} From ea6e1d0a1749bf585217e98dacabd7b9a582fdb5 Mon Sep 17 00:00:00 2001 From: Anthony DePasquale Date: Wed, 8 Apr 2026 13:56:48 +0200 Subject: [PATCH 2/3] ln: use wasi-libc symlink instead of unstable symlink_path --- Cargo.lock | 1 + src/uu/ln/Cargo.toml | 1 + src/uu/ln/src/ln.rs | 24 ++++++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83c1cc8f715..67e7e81dce9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3721,6 +3721,7 @@ version = "0.8.0" dependencies = [ "clap", "fluent", + "libc", "thiserror 2.0.18", "uucore", ] diff --git a/src/uu/ln/Cargo.toml b/src/uu/ln/Cargo.toml index 6527ee89a2b..fbe17621fef 100644 --- a/src/uu/ln/Cargo.toml +++ b/src/uu/ln/Cargo.toml @@ -20,6 +20,7 @@ path = "src/ln.rs" [dependencies] clap = { workspace = true } +libc = { workspace = true } uucore = { workspace = true, features = ["backup-control", "fs"] } thiserror = { workspace = true } fluent = { workspace = true } diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 7556fb2b6e0..35b9d2f67f9 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -3,8 +3,6 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#![cfg_attr(target_os = "wasi", feature(wasi_ext))] - // spell-checker:ignore (ToDO) srcpath targetpath EEXIST use clap::{Arg, ArgAction, Command}; @@ -21,10 +19,12 @@ use std::ffi::OsString; use std::fs; use thiserror::Error; +#[cfg(target_os = "wasi")] +use std::ffi::CString; +#[cfg(target_os = "wasi")] +use std::io; #[cfg(any(unix, target_os = "redox"))] use std::os::unix::fs::symlink; -#[cfg(target_os = "wasi")] -use std::os::wasi::fs::symlink_path as symlink; #[cfg(windows)] use std::os::windows::fs::{symlink_dir, symlink_file}; use std::path::{Path, PathBuf}; @@ -492,3 +492,19 @@ pub fn symlink, P2: AsRef>(src: P1, dst: P2) -> std::io::R symlink_file(src, dst) } } + +#[cfg(target_os = "wasi")] +pub fn symlink, P2: AsRef>(src: P1, dst: P2) -> io::Result<()> { + use std::os::wasi::ffi::OsStrExt; + + let src_c = CString::new(src.as_ref().as_os_str().as_bytes()) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; + let dst_c = CString::new(dst.as_ref().as_os_str().as_bytes()) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; + + if unsafe { libc::symlink(src_c.as_ptr(), dst_c.as_ptr()) } == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } +} From 8b311ddfcb871d31a8a283ef40249dae4c3b3e9e Mon Sep 17 00:00:00 2001 From: Anthony DePasquale Date: Wed, 8 Apr 2026 16:36:13 +0200 Subject: [PATCH 3/3] ln: use rustix::fs::symlink instead of libc + CString on WASI --- Cargo.lock | 2 +- src/uu/ln/Cargo.toml | 2 +- src/uu/ln/src/ln.rs | 15 +-------------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67e7e81dce9..22574e2a1f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3721,7 +3721,7 @@ version = "0.8.0" dependencies = [ "clap", "fluent", - "libc", + "rustix", "thiserror 2.0.18", "uucore", ] diff --git a/src/uu/ln/Cargo.toml b/src/uu/ln/Cargo.toml index fbe17621fef..6b4401e3a9d 100644 --- a/src/uu/ln/Cargo.toml +++ b/src/uu/ln/Cargo.toml @@ -20,7 +20,7 @@ path = "src/ln.rs" [dependencies] clap = { workspace = true } -libc = { workspace = true } +rustix = { workspace = true, features = ["fs"] } uucore = { workspace = true, features = ["backup-control", "fs"] } thiserror = { workspace = true } fluent = { workspace = true } diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 35b9d2f67f9..e67bd6f42f3 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -19,8 +19,6 @@ use std::ffi::OsString; use std::fs; use thiserror::Error; -#[cfg(target_os = "wasi")] -use std::ffi::CString; #[cfg(target_os = "wasi")] use std::io; #[cfg(any(unix, target_os = "redox"))] @@ -495,16 +493,5 @@ pub fn symlink, P2: AsRef>(src: P1, dst: P2) -> std::io::R #[cfg(target_os = "wasi")] pub fn symlink, P2: AsRef>(src: P1, dst: P2) -> io::Result<()> { - use std::os::wasi::ffi::OsStrExt; - - let src_c = CString::new(src.as_ref().as_os_str().as_bytes()) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; - let dst_c = CString::new(dst.as_ref().as_os_str().as_bytes()) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; - - if unsafe { libc::symlink(src_c.as_ptr(), dst_c.as_ptr()) } == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()) - } + rustix::fs::symlink(src.as_ref(), dst.as_ref()).map_err(io::Error::from) }