Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ feat_wasm = [
"base64",
"basenc",
"cut",
"ls",
"date",
"dircolors",
"dirname",
Expand Down
5 changes: 4 additions & 1 deletion src/uu/ls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ path = "src/ls.rs"
ansi-width = { workspace = true }
clap = { workspace = true, features = ["env"] }
glob = { workspace = true }
hostname = { workspace = true }
lscolors = { workspace = true }
rustc-hash = { workspace = true }
selinux = { workspace = true, optional = true }
Expand All @@ -46,6 +45,10 @@ uucore = { workspace = true, features = [
uutils_term_grid = { workspace = true }
fluent = { workspace = true }

# hostname crate does not support WASI (no OS-level hostname API)
[target.'cfg(not(target_os = "wasi"))'.dependencies]
hostname = { workspace = true }

[[bin]]
name = "ls"
path = "src/main.rs"
Expand Down
5 changes: 5 additions & 0 deletions src/uu/ls/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,12 @@ fn classify_file(path: &PathData) -> Option<char> {
}

fn create_hyperlink(name: &OsStr, path: &PathData) -> OsString {
// The `hostname` crate does not support WASI (no OS-level hostname API),
// so we use an empty string for hyperlinks on WASI.
#[cfg(not(target_os = "wasi"))]
static HOSTNAME: LazyLock<OsString> = LazyLock::new(|| hostname::get().unwrap_or_default());
#[cfg(target_os = "wasi")]
static HOSTNAME: LazyLock<OsString> = LazyLock::new(OsString::new);

// OSC 8 hyperlink format: \x1b]8;;URL\x1b\\TEXT\x1b]8;;\x1b\\
// \x1b = ESC, \x1b\\ = ESC backslash
Expand Down
45 changes: 42 additions & 3 deletions src/uucore/src/lib/features/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ macro_rules! has {
pub struct FileInformation(
#[cfg(unix)] nix::sys::stat::FileStat,
#[cfg(windows)] winapi_util::file::Information,
// WASI does not have nix::sys::stat, so we store std::fs::Metadata instead.
#[cfg(target_os = "wasi")] std::fs::Metadata,
);

impl FileInformation {
Expand Down Expand Up @@ -91,6 +93,16 @@ impl FileInformation {
let file = open_options.read(true).open(path.as_ref())?;
Self::from_file(&file)
}
// WASI: use std::fs::metadata / symlink_metadata since nix is not available
#[cfg(target_os = "wasi")]
{
let metadata = if dereference {
std::fs::metadata(path.as_ref())
} else {
std::fs::symlink_metadata(path.as_ref())
};
Ok(Self(metadata?))
}
}

pub fn file_size(&self) -> u64 {
Expand All @@ -103,6 +115,10 @@ impl FileInformation {
{
self.0.file_size()
}
#[cfg(target_os = "wasi")]
{
self.0.len()
}
}

#[cfg(windows)]
Expand Down Expand Up @@ -153,6 +169,9 @@ impl FileInformation {
return self.0.st_nlink.try_into().unwrap();
#[cfg(windows)]
return self.0.number_of_links();
// WASI: nlink is not available in std::fs::Metadata, return 1
#[cfg(target_os = "wasi")]
return 1;
}

#[cfg(unix)]
Expand All @@ -172,6 +191,15 @@ impl PartialEq for FileInformation {
}
}

// WASI: compare by file type and size as a basic heuristic since
// device/inode numbers are not available through std::fs::Metadata.
#[cfg(target_os = "wasi")]
impl PartialEq for FileInformation {
fn eq(&self, other: &Self) -> bool {
self.0.file_type() == other.0.file_type() && self.0.len() == other.0.len()
}
}

#[cfg(target_os = "windows")]
impl PartialEq for FileInformation {
fn eq(&self, other: &Self) -> bool {
Expand All @@ -194,6 +222,10 @@ impl Hash for FileInformation {
self.0.volume_serial_number().hash(state);
self.0.file_index().hash(state);
}
#[cfg(target_os = "wasi")]
{
self.0.len().hash(state);
}
}
}

Expand Down Expand Up @@ -778,11 +810,18 @@ pub fn is_stdin_directory(stdin: &Stdin) -> bool {
}
false
}

// WASI: stdin is never a directory
#[cfg(target_os = "wasi")]
{
let _ = stdin;
false
}
}

pub mod sane_blksize {

#[cfg(not(target_os = "windows"))]
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
use std::{fs::metadata, path::Path};

Expand All @@ -809,12 +848,12 @@ pub mod sane_blksize {
#[cfg(unix)] metadata: &std::fs::Metadata,
#[cfg(not(unix))] _: &std::fs::Metadata,
) -> u64 {
#[cfg(not(target_os = "windows"))]
#[cfg(unix)]
{
sane_blksize(metadata.blksize())
}

#[cfg(target_os = "windows")]
#[cfg(not(unix))]
{
DEFAULT
}
Expand Down
5 changes: 3 additions & 2 deletions src/uucore/src/lib/features/fsext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,11 @@ pub fn read_fs_list() -> UResult<Vec<MountInfo>> {
target_os = "aix",
target_os = "redox",
target_os = "illumos",
target_os = "solaris"
target_os = "solaris",
target_os = "wasi"
))]
{
// No method to read mounts, yet
// No method to read mounts on these platforms
Ok(Vec::new())
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/uucore/src/lib/mods/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,17 @@ impl OwnedFileDescriptorOrHandle {
}

/// instantiates a corresponding `Stdio`
#[cfg(not(target_os = "wasi"))]
pub fn into_stdio(self) -> Stdio {
Stdio::from(self.fx)
}

/// WASI: Stdio::from(OwnedFd) is not available, convert via File instead.
#[cfg(target_os = "wasi")]
pub fn into_stdio(self) -> Stdio {
Stdio::from(File::from(self.fx))
}

/// clones self. useful when needing another
/// owned reference to same file
pub fn try_clone(&self) -> io::Result<Self> {
Expand Down
Loading