build: support compiling for non-Unix targets such as wasm

The platform-specific code was split into cfg(unix)/cfg(windows) arms, so
wasm32 targets (which are neither) failed to compile. Widen the generic
Windows stubs to cfg(not(unix)) and make the -ls printer and xargs size
limiters fall back to portable APIs when no platform-specific one exists.
This commit is contained in:
Sylvestre Ledru
2026-06-10 07:45:04 +02:00
parent 5bf236b891
commit c100ac226f
8 changed files with 47 additions and 22 deletions
+7 -5
View File
@@ -11,6 +11,8 @@ use nix::unistd::Group;
use std::os::unix::fs::MetadataExt;
pub struct GroupMatcher {
// Only read on Unix; the non-Unix `matches` implementation is a stub.
#[cfg_attr(not(unix), allow(dead_code))]
gid: ComparableValue,
}
@@ -31,7 +33,7 @@ impl GroupMatcher {
Self { gid }
}
#[cfg(windows)]
#[cfg(not(unix))]
pub fn from_group_name(_group: &str) -> Option<Self> {
None
}
@@ -46,10 +48,10 @@ impl Matcher for GroupMatcher {
}
}
#[cfg(windows)]
#[cfg(not(unix))]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
// The user group acquisition function for Windows systems is not implemented in MetadataExt,
// so it is somewhat difficult to implement it. :(
// The user group acquisition function for non-Unix systems is not implemented in
// MetadataExt, so it is somewhat difficult to implement it. :(
false
}
}
@@ -80,7 +82,7 @@ impl Matcher for NoGroupMatcher {
false
}
#[cfg(windows)]
#[cfg(not(unix))]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
+14 -10
View File
@@ -195,7 +195,7 @@ impl Ls {
}
}
#[cfg(windows)]
#[cfg(not(unix))]
fn print(
&self,
file_info: &WalkEntry,
@@ -203,16 +203,15 @@ impl Ls {
mut out: impl Write,
print_error_message: bool,
) {
use std::os::windows::fs::MetadataExt;
// Non-Unix targets (Windows, wasm, ...) don't expose inode, owner,
// group or Unix permission bits, so those columns are left blank.
let metadata = file_info.metadata().unwrap();
let inode_number = 0;
let size = metadata.len();
let number_of_blocks = {
let size = metadata.file_size();
let number_of_blocks = size / 1024;
let remainder = number_of_blocks % 4;
if remainder == 0 {
if number_of_blocks == 0 {
4
@@ -220,14 +219,19 @@ impl Ls {
number_of_blocks
}
} else {
number_of_blocks + (4 - (remainder))
number_of_blocks + (4 - remainder)
}
};
let permission = { format_permissions(metadata.file_attributes()) };
#[cfg(windows)]
let permission = {
use std::os::windows::fs::MetadataExt;
format_permissions(metadata.file_attributes())
};
#[cfg(not(windows))]
let permission = "?---------";
let hard_links = 0;
let user = 0;
let group = 0;
let size = metadata.file_size();
let last_modified = {
let system_time = metadata.modified().unwrap();
let now_utc: DateTime<chrono::Utc> = system_time.into();
@@ -235,9 +239,9 @@ impl Ls {
};
let path = file_info.path().to_string_lossy();
match write!(
match writeln!(
out,
" {:<4} {:>6} {:<10} {:>3} {:<8} {:<8} {:>8} {} {}\n",
" {:<4} {:>6} {:<10} {:>3} {:<8} {:<8} {:>8} {} {}",
inode_number,
number_of_blocks,
permission,
+1 -1
View File
@@ -31,7 +31,7 @@ impl Matcher for NameMatcher {
self.pattern.matches(&name)
}
#[cfg(windows)]
#[cfg(not(unix))]
self.pattern.matches(&name)
}
}
+2 -2
View File
@@ -91,7 +91,7 @@ impl PermMatcher {
}
#[cfg(not(unix))]
pub fn new(_dummy_pattern: &str) -> Result<PermMatcher, Box<dyn Error>> {
pub fn new(_dummy_pattern: &str) -> Result<Self, Box<dyn Error>> {
Err(From::from(
"Permission matching is not available on this platform",
))
@@ -132,7 +132,7 @@ impl Matcher for PermMatcher {
"Permission matching not available on this platform!"
)
.unwrap();
return false;
false
}
}
+1
View File
@@ -17,6 +17,7 @@ use super::{FileType, Matcher, MatcherIO, WalkEntry, WalkError};
#[cfg(unix)]
use std::os::unix::prelude::MetadataExt;
#[cfg(unix)]
const STANDARD_BLOCK_SIZE: u64 = 512;
#[derive(Debug, PartialEq, Eq)]
+5 -3
View File
@@ -11,6 +11,8 @@ use nix::unistd::User;
use std::os::unix::fs::MetadataExt;
pub struct UserMatcher {
// Only read on Unix; the non-Unix `matches` implementation is a stub.
#[cfg_attr(not(unix), allow(dead_code))]
uid: ComparableValue,
}
@@ -31,7 +33,7 @@ impl UserMatcher {
Self { uid }
}
#[cfg(windows)]
#[cfg(not(unix))]
pub fn from_user_name(_user: &str) -> Option<Self> {
None
}
@@ -46,7 +48,7 @@ impl Matcher for UserMatcher {
}
}
#[cfg(windows)]
#[cfg(not(unix))]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
@@ -78,7 +80,7 @@ impl Matcher for NoUserMatcher {
false
}
#[cfg(windows)]
#[cfg(not(unix))]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
+3 -1
View File
@@ -9,7 +9,9 @@ pub mod matchers;
use matchers::{Follow, WalkEntry};
use std::cell::RefCell;
use std::error::Error;
use std::io::{self, stderr, stdout, BufRead, BufReader, IsTerminal, Write};
#[cfg(unix)]
use std::io::IsTerminal;
use std::io::{self, stderr, stdout, BufRead, BufReader, Write};
use std::path::PathBuf;
use std::rc::Rc;
use std::time::SystemTime;
+14
View File
@@ -152,6 +152,12 @@ fn count_osstr_chars_for_exec(s: &OsStr) -> usize {
s.as_bytes().len() + 1
}
#[cfg(not(any(unix, windows)))]
fn count_osstr_chars_for_exec(s: &OsStr) -> usize {
// Include +1 for the null terminator.
s.as_encoded_bytes().len() + 1
}
#[derive(Clone)]
struct MaxCharsCommandSizeLimiter {
current_size: usize,
@@ -187,6 +193,14 @@ impl MaxCharsCommandSizeLimiter {
Self::new(arg_max - ARG_HEADROOM - env_size)
}
#[cfg(not(any(unix, windows)))]
fn new_system(_env: &HashMap<OsString, OsString>) -> Self {
// No portable way to query the system limit; fall back to the POSIX
// minimum guaranteed value for _POSIX_ARG_MAX.
const POSIX_ARG_MAX: usize = 4096;
Self::new(POSIX_ARG_MAX)
}
}
impl CommandSizeLimiter for MaxCharsCommandSizeLimiter {