diff --git a/Cargo.lock b/Cargo.lock index af7c96e..5ce7a92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,6 +272,7 @@ dependencies = [ "pretty_assertions", "rand", "regex", + "rustix", "same-file", "tempfile", "unicode-width", @@ -645,9 +646,9 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ "bitflags", "errno", diff --git a/Cargo.toml b/Cargo.toml index ded812c..03fedb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,9 @@ regex = "1.10.4" same-file = "1.0.6" unicode-width = "0.2.0" +[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] +rustix = { version = "1.1.5", features = ["fs"] } + [dev-dependencies] assert_cmd = "2.0.14" divan = { version = "5.0.0", package = "codspeed-divan-compat" } diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 47a03af..ae38cf3 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -32,6 +32,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + [[package]] name = "bumpalo" version = "3.20.2" @@ -89,10 +95,21 @@ dependencies = [ "diff", "itoa", "regex", + "rustix", "same-file", "unicode-width", ] +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -177,6 +194,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "log" version = "0.4.29" @@ -257,6 +280,19 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.22" diff --git a/src/cmp.rs b/src/cmp.rs index e3534a0..9a789a0 100644 --- a/src/cmp.rs +++ b/src/cmp.rs @@ -11,12 +11,6 @@ use std::iter::Peekable; use std::process::ExitCode; use std::{cmp, fs, io}; -#[cfg(unix)] -use std::os::fd::{AsRawFd, FromRawFd}; - -#[cfg(unix)] -use std::os::unix::fs::MetadataExt; - #[cfg(target_os = "windows")] use std::os::windows::fs::MetadataExt; @@ -43,8 +37,26 @@ fn usage_string(executable: &str) -> String { format!("Usage: {executable} ") } +#[cfg(any(target_os = "linux", target_os = "android"))] +fn is_stdout_dev_null() -> bool { + // as_fd().try_clone_to_owned() needs additional overhead of fcntl + use rustix::fs; + let stdout = io::stdout(); + let Ok(stat) = fs::fstat(stdout) else { + return false; + }; + let dev = stat.st_rdev; + + let is_char_device = fs::FileType::from_raw_mode(stat.st_mode).is_char_device(); + // /dev/null's major/minor is frozen on Linux. So we don't need to open new `/dev/null` and compare + is_char_device && fs::major(dev) == 1 && fs::minor(dev) == 3 +} + #[cfg(unix)] +#[cfg(not(any(target_os = "linux", target_os = "android")))] fn is_stdout_dev_null() -> bool { + use std::os::fd::{AsRawFd, FromRawFd}; + use std::os::unix::fs::MetadataExt; let Ok(dev_null) = fs::metadata("/dev/null") else { return false; };