Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,3 @@ diff -ruN '--exclude=*.orig' a/src/reedline/validator.rs b/src/reedline/validato
let shell = tokio::task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(self.shell.lock())
});
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -91,6 +91,13 @@
"signal",
]

+[target."cfg(target_arch = \"wasm32\")".dependencies.tokio]
+version = "1.48.0"
+features = [
+ "macros",
+ "sync",
+]
+
[target."cfg(unix)".dependencies.nix]
version = "0.30.1"
features = ["term"]
89 changes: 71 additions & 18 deletions registry/native/patches/crates/uu_chmod/0001-wasi-compat.patch
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--- a/src/chmod.rs
+++ b/src/chmod.rs
@@ -8,16 +8,70 @@
@@ -8,16 +8,87 @@
use clap::{Arg, ArgAction, Command};
use std::ffi::OsString;
use std::fs;
Expand All @@ -27,23 +27,42 @@
+ mod host_fs {
+ #[link(wasm_import_module = "host_fs")]
+ unsafe extern "C" {
+ pub fn chmod(path_ptr: *const u8, path_len: u32, mode: u32) -> u32;
+ pub fn chmod(fd: u32, path_ptr: *const u8, path_len: u32, mode: u32) -> u32;
+ pub fn path_mode(
+ fd: u32,
+ path_ptr: *const u8,
+ path_len: u32,
+ follow_symlinks: u32,
+ ) -> u32;
+ }
+ }
+
+ /// Extension trait to provide mode() on WASI Metadata.
+ pub trait MetadataMode {
+ fn mode(&self) -> u32;
+ fn fallback_mode(meta: &fs::Metadata) -> u32 {
+ let ft = meta.file_type();
+ let base = if ft.is_dir() { 0o755 } else { 0o644 };
+ if meta.permissions().readonly() {
+ base & !0o222
+ } else {
+ base
+ }
+ }
+ impl MetadataMode for fs::Metadata {
+ fn mode(&self) -> u32 {
+ let ft = self.file_type();
+ let base = if ft.is_dir() { 0o755 } else { 0o644 };
+ if self.permissions().readonly() {
+ base & !0o222
+ } else {
+ base
+ }
+
+ pub fn mode_for_path(path: &Path, meta: &fs::Metadata, follow_symlinks: bool) -> u32 {
+ let Some(path_str) = path.to_str() else {
+ return fallback_mode(meta);
+ };
+ let mode = unsafe {
+ host_fs::path_mode(
+ 3,
+ path_str.as_ptr(),
+ path_str.len() as u32,
+ if follow_symlinks { 1 } else { 0 },
+ )
+ };
+ if mode == 0 {
+ fallback_mode(meta)
+ } else {
+ mode & 0o7777
+ }
+ }
+
Expand All @@ -55,7 +74,7 @@
+ .to_str()
+ .ok_or_else(|| Error::new(ErrorKind::InvalidInput, "path is not valid UTF-8"))?
+ .as_bytes();
+ let status = unsafe { host_fs::chmod(bytes.as_ptr(), bytes.len() as u32, mode) };
+ let status = unsafe { host_fs::chmod(3, bytes.as_ptr(), bytes.len() as u32, mode) };
+ if status == 0 {
+ return Ok(());
+ }
Expand All @@ -65,13 +84,47 @@
+ fs::set_permissions(path, perms)
+ }
+}
+#[cfg(target_os = "wasi")]
+use wasi_compat::MetadataMode;
+
#[cfg(all(unix, not(target_os = "redox")))]
use uucore::safe_traversal::{DirFd, SymlinkBehavior};
use uucore::{format_usage, show, show_error};
@@ -683,7 +737,12 @@
@@ -121,7 +192,16 @@
let preserve_root = matches.get_flag(options::PRESERVE_ROOT);
let fmode = match matches.get_one::<OsString>(options::REFERENCE) {
Some(fref) => match fs::metadata(fref) {
- Ok(meta) => Some(meta.mode() & 0o7777),
+ Ok(meta) => {
+ #[cfg(target_os = "wasi")]
+ {
+ Some(wasi_compat::mode_for_path(Path::new(fref), &meta, true))
+ }
+ #[cfg(not(target_os = "wasi"))]
+ {
+ Some(meta.mode() & 0o7777)
+ }
+ }
Err(_) => {
return Err(ChmodError::CannotStat(fref.into()).into());
}
@@ -623,7 +703,16 @@
let metadata = get_metadata(file, dereference);

let fperm = match metadata {
- Ok(meta) => meta.mode() & 0o7777,
+ Ok(meta) => {
+ #[cfg(target_os = "wasi")]
+ {
+ wasi_compat::mode_for_path(file, &meta, dereference)
+ }
+ #[cfg(not(target_os = "wasi"))]
+ {
+ meta.mode() & 0o7777
+ }
+ }
Err(err) => {
// Handle dangling symlinks or other errors
return if file.is_symlink() && !dereference {
@@ -683,7 +772,12 @@
// Use the helper method for consistent reporting
self.report_permission_change(file, fperm, mode);
Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
fsext::{MetadataTimeField, metadata_get_time},
line_ending::LineEnding,
os_str_as_bytes_lossy,
@@ -77,6 +77,38 @@
@@ -77,6 +77,60 @@
translate,
version_cmp::version_cmp,
};
Expand All @@ -18,37 +18,59 @@
+
+#[cfg(target_os = "wasi")]
+mod wasi_host_fs {
+ use std::env;
+
+ use super::{Metadata, Path};
+
+ mod host_fs {
+ #[link(wasm_import_module = "host_fs")]
+ unsafe extern "C" {
+ pub fn path_mode(path_ptr: *const u8, path_len: u32, follow_symlinks: u32) -> u32;
+ pub fn path_mode(
+ fd: u32,
+ path_ptr: *const u8,
+ path_len: u32,
+ follow_symlinks: u32,
+ ) -> u32;
+ }
+ }
+
+ pub fn mode_for_path(path: &Path, metadata: &Metadata, follow_symlinks: bool) -> u32 {
+ fn fallback_mode(metadata: &Metadata) -> u32 {
+ if metadata.is_dir() { 0o040755 } else { 0o100644 }
+ }
+
+ fn raw_mode_for_path(path: &Path, follow_symlinks: bool) -> u32 {
+ let Some(path_str) = path.to_str() else {
+ return if metadata.is_dir() { 0o040755 } else { 0o100644 };
+ return 0;
+ };
+ let mode = unsafe {
+ unsafe {
+ host_fs::path_mode(
+ 3,
+ path_str.as_ptr(),
+ path_str.len() as u32,
+ if follow_symlinks { 1 } else { 0 },
+ )
+ };
+ if mode == 0 {
+ if metadata.is_dir() { 0o040755 } else { 0o100644 }
+ } else {
+ }
+ }
+
+ pub fn mode_for_path(path: &Path, metadata: &Metadata, follow_symlinks: bool) -> u32 {
+ let mode = raw_mode_for_path(path, follow_symlinks);
+ if mode != 0 {
+ mode
+ } else if path.is_relative() {
+ env::current_dir()
+ .ok()
+ .map(|cwd| raw_mode_for_path(&cwd.join(path), follow_symlinks))
+ .filter(|mode| *mode != 0)
+ .unwrap_or_else(|| fallback_mode(metadata))
+ } else {
+ fallback_mode(metadata)
+ }
+ }
+}

mod dired;
use dired::{DiredOutput, is_dired_arg_present};
@@ -2982,7 +3014,15 @@
@@ -2982,7 +3036,15 @@
let is_acl_set = false;
#[cfg(all(unix, not(any(target_os = "android", target_os = "macos"))))]
let is_acl_set = has_acl(item.path());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
use uucore::{entries, format_usage, show_error, show_warning};

use clap::{Arg, ArgAction, ArgMatches, Command};
@@ -23,10 +29,79 @@
@@ -23,10 +29,85 @@
use std::ffi::{OsStr, OsString};
use std::fs::{FileType, Metadata};
use std::io::Write;
Expand Down Expand Up @@ -79,7 +79,12 @@
+ mod host_fs {
+ #[link(wasm_import_module = "host_fs")]
+ unsafe extern "C" {
+ pub fn path_mode(path_ptr: *const u8, path_len: u32, follow_symlinks: u32) -> u32;
+ pub fn path_mode(
+ fd: u32,
+ path_ptr: *const u8,
+ path_len: u32,
+ follow_symlinks: u32,
+ ) -> u32;
+ }
+ }
+
Expand All @@ -89,6 +94,7 @@
+ };
+ let mode = unsafe {
+ host_fs::path_mode(
+ 3,
+ path_str.as_ptr(),
+ path_str.len() as u32,
+ if follow_symlinks { 1 } else { 0 },
Expand All @@ -105,15 +111,16 @@
use thiserror::Error;
use uucore::time::{FormatSystemTimeFallback, format_system_time, system_time_to_sec};

@@ -1048,11 +1123,16 @@
precision,
format,
@@ -1032,6 +1113,7 @@
display_name: &str,
file: &OsString,
file_type: FileType,
+ effective_mode: u32,
from_user: bool,
#[cfg(all(feature = "selinux", any(target_os = "linux", target_os = "android")))]
follow_symbolic_links: bool,
@@ -1050,9 +1132,9 @@
} => {
+ #[cfg(target_os = "wasi")]
+ let effective_mode =
+ wasi_host_fs::mode_for_path(Path::new(file), meta, self.follow);
+ #[cfg(not(target_os = "wasi"))]
+ let effective_mode = meta.mode();
let output = match format {
// access rights in octal
- 'a' => OutputType::UnsignedOct(0o7777 & meta.mode()),
Expand All @@ -124,7 +131,7 @@
// number of blocks allocated (see %B)
'b' => OutputType::Unsigned(meta.blocks()),

@@ -1096,9 +1176,9 @@
@@ -1096,9 +1178,9 @@
// device number in hex
'D' => OutputType::UnsignedHex(meta.dev()),
// raw mode in hex
Expand All @@ -136,3 +143,23 @@
// group ID of owner
'g' => OutputType::Unsigned(meta.gid() as u64),
// group name of owner
@@ -1234,6 +1316,11 @@
match result {
Ok(meta) => {
let file_type = meta.file_type();
+ #[cfg(target_os = "wasi")]
+ let effective_mode =
+ wasi_host_fs::mode_for_path(Path::new(&file), &meta, follow_symbolic_links);
+ #[cfg(not(target_os = "wasi"))]
+ let effective_mode = meta.mode();
let tokens = if self.from_user
|| !(file_type.is_char_device() || file_type.is_block_device())
{
@@ -1249,6 +1336,7 @@
&display_name,
&file,
file_type,
+ effective_mode,
self.from_user,
follow_symbolic_links,
) {
9 changes: 5 additions & 4 deletions registry/native/scripts/patch-vendor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,15 @@ for CRATE_DIR in $CRATE_DIRS; do
patch -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1
echo "applied"
elif patch --dry-run -R -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1; then
patch -R -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1
patch -p1 -d "$VENDOR_CRATE" < "$PATCH" > /dev/null 2>&1
echo "reapplied"
echo "already applied"
else
# Mixed state (e.g. an interrupted earlier run left some
# hunks applied): apply the remaining hunks, tolerating
# already-applied ones; fail only on genuine rejects.
OUT=$(patch -p1 -N -r /dev/null -d "$VENDOR_CRATE" < "$PATCH" 2>&1); RC=$?
set +e
OUT=$(patch -p1 -N -r /dev/null -d "$VENDOR_CRATE" < "$PATCH" 2>&1)
RC=$?
set -e
if [ $RC -le 1 ] && ! echo "$OUT" | grep -q "FAILED"; then
echo "converged (mixed state)"
else
Expand Down
19 changes: 9 additions & 10 deletions registry/native/stubs/uucore/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,16 +252,15 @@ fn embed_static_utility_locales(
for entry in entries {
let file_name = entry.file_name();
if let Some(dir_name) = file_name.to_str() {
// Match uu_<util>-<version>
if let Some((util_part, _)) = dir_name.split_once('-') {
if let Some(util_name) = util_part.strip_prefix("uu_") {
embed_component_locales(
embedded_file,
locales_to_embed,
util_name,
|locale| entry.path().join(format!("locales/{locale}.ftl")),
)?;
}
// Match cargo-vendor's uu_<util> directories and registry uu_<util>-<version> names.
let util_part = dir_name.split_once('-').map_or(dir_name, |(name, _)| name);
if let Some(util_name) = util_part.strip_prefix("uu_") {
embed_component_locales(
embedded_file,
locales_to_embed,
util_name,
|locale| entry.path().join(format!("locales/{locale}.ftl")),
)?;
}
}
}
Expand Down