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
4 changes: 3 additions & 1 deletion src/uu/env/src/native_int_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
// this conversion needs to be done only once in the beginning and at the end.

use std::ffi::OsString;
#[cfg(not(target_os = "windows"))]
#[cfg(unix)]
use std::os::unix::ffi::{OsStrExt, OsStringExt};
#[cfg(target_os = "wasi")]
use std::os::wasi::ffi::{OsStrExt, OsStringExt};
#[cfg(target_os = "windows")]
use std::os::windows::prelude::*;
use std::{borrow::Cow, ffi::OsStr};
Expand Down
51 changes: 10 additions & 41 deletions src/uucore/src/lib/features/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::fs::read_dir;
use std::hash::Hash;
use std::io::Stdin;
use std::io::{Error, ErrorKind, Result as IOResult};
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
use std::os::fd::AsFd;
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
Expand All @@ -39,15 +39,13 @@ macro_rules! has {

/// Information to uniquely identify a file
pub struct FileInformation(
#[cfg(unix)] rustix::fs::Stat,
#[cfg(any(unix, target_os = "wasi"))] rustix::fs::Stat,
#[cfg(windows)] winapi_util::file::Information,
// WASI does not have nix::sys::stat, so we store std::fs::Metadata instead.
#[cfg(target_os = "wasi")] fs::Metadata,
);

impl FileInformation {
/// Get information from a currently open file
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
pub fn from_file(file: &impl AsFd) -> IOResult<Self> {
let stat = rustix::fs::fstat(file)?;
Ok(Self(stat))
Expand All @@ -65,7 +63,7 @@ impl FileInformation {
/// If `path` points to a symlink and `dereference` is true, information about
/// the link's target will be returned.
pub fn from_path(path: impl AsRef<Path>, dereference: bool) -> IOResult<Self> {
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
{
let stat = if dereference {
rustix::fs::stat(path.as_ref())
Expand All @@ -89,20 +87,10 @@ 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 {
fs::metadata(path.as_ref())
} else {
fs::symlink_metadata(path.as_ref())
};
Ok(Self(metadata?))
}
}

pub fn file_size(&self) -> u64 {
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
{
assert!(self.0.st_size >= 0, "File size is negative");
self.0.st_size.try_into().unwrap()
Expand All @@ -111,10 +99,6 @@ impl FileInformation {
{
self.0.file_size()
}
#[cfg(target_os = "wasi")]
{
self.0.len()
}
}

#[cfg(windows)]
Expand All @@ -141,6 +125,8 @@ impl FileInformation {
target_pointer_width = "64"
))]
return self.0.st_nlink;
#[cfg(target_os = "wasi")]
return self.0.st_nlink;
#[cfg(all(
unix,
any(
Expand All @@ -165,12 +151,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)]
#[cfg(any(unix, target_os = "wasi"))]
pub fn inode(&self) -> u64 {
#[cfg(all(not(any(target_os = "netbsd")), target_pointer_width = "64"))]
return self.0.st_ino;
Expand All @@ -180,22 +163,13 @@ impl FileInformation {
}
}

#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
impl PartialEq for FileInformation {
fn eq(&self, other: &Self) -> bool {
self.0.st_dev == other.0.st_dev && self.0.st_ino == other.0.st_ino
}
}

// 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 @@ -208,7 +182,7 @@ impl Eq for FileInformation {}

impl Hash for FileInformation {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
{
self.0.st_dev.hash(state);
self.0.st_ino.hash(state);
Expand All @@ -218,11 +192,6 @@ 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);
self.0.file_type().is_dir().hash(state);
}
}
}

Expand Down
11 changes: 2 additions & 9 deletions src/uucore/src/lib/features/fsext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,6 @@ fn mount_dev_id(mount_dir: &OsStr) -> String {
}
}

#[cfg(not(target_os = "wasi"))]
use crate::error::UResult;
#[cfg(any(
target_os = "freebsd",
Expand Down Expand Up @@ -459,7 +458,7 @@ use std::ptr;
use std::slice;

/// Read file system list.
#[cfg(not(target_os = "wasi"))]
#[cfg_attr(target_os = "wasi", allow(clippy::unnecessary_wraps))]
pub fn read_fs_list() -> UResult<Vec<MountInfo>> {
#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
{
Expand Down Expand Up @@ -540,20 +539,14 @@ pub fn read_fs_list() -> UResult<Vec<MountInfo>> {
target_os = "redox",
target_os = "illumos",
target_os = "solaris",
target_os = "wasi"
))]
{
// No method to read mounts on these platforms
Ok(Vec::new())
}
}

/// Read file system list.
#[cfg(target_os = "wasi")]
pub fn read_fs_list() -> Vec<MountInfo> {
// No method to read mounts on WASI
Vec::new()
}

#[derive(Debug, Clone)]
pub struct FsUsage {
pub blocksize: u64,
Expand Down
9 changes: 1 addition & 8 deletions src/uucore/src/lib/mods/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,7 @@ impl OwnedFileDescriptorOrHandle {
/// instantiates a corresponding `Stdio`
#[cfg(not(target_os = "wasi"))]
pub fn into_stdio(self) -> Stdio {
#[cfg(not(target_os = "wasi"))]
{
Stdio::from(self.fx)
}
#[cfg(target_os = "wasi")]
{
Stdio::from(File::from(self.fx))
}
Stdio::from(self.fx)
}

/// WASI: Stdio::from(OwnedFd) is not available, convert via File instead.
Expand Down
63 changes: 26 additions & 37 deletions tests/by-util/test_comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,17 +455,12 @@ fn test_sorted() {
let at = &scene.fixtures;
at.write("comm1", "1\n3");
at.write("comm2", "3\n2");
let cmd = scene.ucmd().args(&["comm1", "comm2"]).run();
// WASI's strcoll (C locale only) may not detect unsorted input,
// but the comparison output is still correct.
if std::env::var("UUTESTS_WASM_RUNNER").is_ok() {
cmd.success().stdout_is("1\n\t\t3\n\t2\n");
} else {
cmd.failure()
.code_is(1)
.stdout_is("1\n\t\t3\n\t2\n")
.stderr_is("comm: file 2 is not in sorted order\ncomm: input is not in sorted order\n");
}
scene
.ucmd()
.args(&["comm1", "comm2"])
.fails_with_code(1)
.stdout_is("1\n\t\t3\n\t2\n")
.stderr_is("comm: file 2 is not in sorted order\ncomm: input is not in sorted order\n");
}

#[test]
Expand All @@ -492,19 +487,16 @@ fn test_both_inputs_out_of_order() {
at.write("file_a", "3\n1\n0\n");
at.write("file_b", "3\n2\n0\n");

let cmd = scene.ucmd().args(&["file_a", "file_b"]).run();
if std::env::var("UUTESTS_WASM_RUNNER").is_ok() {
cmd.success().stdout_is("\t\t3\n1\n0\n\t2\n\t0\n");
} else {
cmd.failure()
.code_is(1)
.stdout_is("\t\t3\n1\n0\n\t2\n\t0\n")
.stderr_is(
"comm: file 1 is not in sorted order\n\
comm: file 2 is not in sorted order\n\
comm: input is not in sorted order\n",
);
}
scene
.ucmd()
.args(&["file_a", "file_b"])
.fails_with_code(1)
.stdout_is("\t\t3\n1\n0\n\t2\n\t0\n")
.stderr_is(
"comm: file 1 is not in sorted order\n\
comm: file 2 is not in sorted order\n\
comm: input is not in sorted order\n",
);
}

#[test]
Expand All @@ -514,19 +506,16 @@ fn test_both_inputs_out_of_order_last_pair() {
at.write("file_a", "3\n1\n");
at.write("file_b", "3\n2\n");

let cmd = scene.ucmd().args(&["file_a", "file_b"]).run();
if std::env::var("UUTESTS_WASM_RUNNER").is_ok() {
cmd.success().stdout_is("\t\t3\n1\n\t2\n");
} else {
cmd.failure()
.code_is(1)
.stdout_is("\t\t3\n1\n\t2\n")
.stderr_is(
"comm: file 1 is not in sorted order\n\
comm: file 2 is not in sorted order\n\
comm: input is not in sorted order\n",
);
}
scene
.ucmd()
.args(&["file_a", "file_b"])
.fails_with_code(1)
.stdout_is("\t\t3\n1\n\t2\n")
.stderr_is(
"comm: file 1 is not in sorted order\n\
comm: file 2 is not in sorted order\n\
comm: input is not in sorted order\n",
);
}

#[test]
Expand Down
1 change: 0 additions & 1 deletion tests/by-util/test_tr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,6 @@ fn test_truncate_with_set1_shorter_than_set2() {
fn test_truncate_applies_before_complement_with_class() {
new_ucmd!()
.args(&["-ct", "[:digit:]", "X"])
.pipe_in("A")
.fails()
.stderr_contains("when translating with complemented character classes,\nstring2 must map all characters in the domain to one");
}
Expand Down
Loading