Skip to content

Commit

Permalink
stat: improve handling of stdin/fifo (fix uutils#3485)
Browse files Browse the repository at this point in the history
* fix uutils#3485
* improve the workaround from uutils#3280
* add tests
  • Loading branch information
jhscheer committed May 6, 2022
1 parent f5ffa94 commit cba5205
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 36 deletions.
76 changes: 45 additions & 31 deletions src/uu/stat/src/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use uucore::{entries, format_usage};
use clap::{crate_version, Arg, ArgMatches, Command};
use std::borrow::Cow;
use std::convert::AsRef;
use std::ffi::{OsStr, OsString};
use std::os::unix::fs::{FileTypeExt, MetadataExt};
use std::os::unix::prelude::OsStrExt;
use std::path::Path;
use std::{cmp, fs, iter};

Expand Down Expand Up @@ -221,7 +223,7 @@ pub struct Stater {
follow: bool,
show_fs: bool,
from_user: bool,
files: Vec<String>,
files: Vec<OsString>,
mount_list: Option<Vec<String>>,
default_tokens: Vec<Token>,
default_dev_tokens: Vec<Token>,
Expand Down Expand Up @@ -471,24 +473,10 @@ impl Stater {
}

fn new(matches: &ArgMatches) -> UResult<Self> {
let mut files: Vec<String> = matches
let files = matches
.values_of(ARG_FILES)
.map(|v| v.map(ToString::to_string).collect())
.map(|v| v.map(OsString::from).collect())
.unwrap_or_default();
#[cfg(unix)]
if files.contains(&String::from("-")) {
let redirected_path = Path::new("/dev/stdin")
.canonicalize()
.expect("unable to canonicalize /dev/stdin")
.into_os_string()
.into_string()
.unwrap();
for file in &mut files {
if file == "-" {
*file = redirected_path.clone();
}
}
}
let format_str = if matches.is_present(options::PRINTF) {
matches
.value_of(options::PRINTF)
Expand Down Expand Up @@ -550,19 +538,37 @@ impl Stater {
}

fn exec(&self) -> i32 {
let mut stdin_is_fifo = false;
if cfg!(unix) {
if let Ok(md) = fs::metadata("/dev/stdin") {
stdin_is_fifo = md.file_type().is_fifo();
}
}

let mut ret = 0;
for f in &self.files {
ret |= self.do_stat(f.as_str());
ret |= self.do_stat(f, stdin_is_fifo);
}
ret
}

fn do_stat(&self, file: &str) -> i32 {
fn do_stat(&self, file: &OsStr, stdin_is_fifo: bool) -> i32 {
let display_name = file.to_string_lossy();
let file: OsString = if cfg!(unix) && display_name.eq("-") {
if let Ok(p) = Path::new("/dev/stdin").canonicalize() {
p.into_os_string()
} else {
OsString::from("/dev/stdin")
}
} else {
OsString::from(file)
};

if !self.show_fs {
let result = if self.follow {
fs::metadata(file)
let result = if self.follow || stdin_is_fifo && display_name.eq("-") {
fs::metadata(&file)
} else {
fs::symlink_metadata(file)
fs::symlink_metadata(&file)
};
match result {
Ok(meta) => {
Expand Down Expand Up @@ -658,28 +664,32 @@ impl Stater {

// mount point
'm' => {
arg = self.find_mount_point(file).unwrap();
arg = self.find_mount_point(&file).unwrap();
output_type = OutputType::Str;
}

// file name
'n' => {
arg = file.to_owned();
arg = display_name.to_string();
output_type = OutputType::Str;
}
// quoted file name with dereference if symbolic link
'N' => {
if file_type.is_symlink() {
let dst = match fs::read_link(file) {
let dst = match fs::read_link(&file) {
Ok(path) => path,
Err(e) => {
println!("{}", e);
return 1;
}
};
arg = format!("{} -> {}", file.quote(), dst.quote());
arg = format!(
"{} -> {}",
display_name.quote(),
dst.quote()
);
} else {
arg = file.to_string();
arg = display_name.to_string();
}
output_type = OutputType::Str;
}
Expand Down Expand Up @@ -771,12 +781,16 @@ impl Stater {
}
}
Err(e) => {
show_error!("cannot stat {}: {}", file.quote(), e);
show_error!("cannot stat {}: {}", display_name.quote(), e);
return 1;
}
}
} else {
match statfs(file) {
#[cfg(unix)]
let p = file.as_bytes();
#[cfg(not(unix))]
let p = file.into_string().unwrap();
match statfs(p) {
Ok(meta) => {
let tokens = &self.default_tokens;

Expand Down Expand Up @@ -829,7 +843,7 @@ impl Stater {
}
// file name
'n' => {
arg = file.to_owned();
arg = display_name.to_string();
output_type = OutputType::Str;
}
// block size (for faster transfers)
Expand Down Expand Up @@ -866,7 +880,7 @@ impl Stater {
Err(e) => {
show_error!(
"cannot read file system information for {}: {}",
file.quote(),
display_name.quote(),
e
);
return 1;
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 @@ -84,6 +84,7 @@ use std::ffi::CString;
use std::io::Error as IOError;
#[cfg(unix)]
use std::mem;
#[cfg(not(unix))]
use std::path::Path;
use std::time::UNIX_EPOCH;

Expand Down Expand Up @@ -708,9 +709,9 @@ impl FsMeta for StatFs {
}

#[cfg(unix)]
pub fn statfs<P: AsRef<Path>>(path: P) -> Result<StatFs, String>
pub fn statfs<P>(path: P) -> Result<StatFs, String>
where
Vec<u8>: From<P>,
P: Into<Vec<u8>>,
{
match CString::new(path) {
Ok(p) => {
Expand Down
26 changes: 23 additions & 3 deletions tests/by-util/test_stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,19 @@ fn test_printf() {

#[cfg(unix)]
#[test]
#[cfg(disable_until_fixed)]
fn test_pipe_fifo() {
let (at, mut ucmd) = at_and_ucmd!();
at.mkfifo("FIFO");
ucmd.arg("FIFO")
.run()
.no_stderr()
.stdout_contains("fifo")
.stdout_contains("File: FIFO")
.succeeded();
}

#[cfg(unix)]
#[test]
fn test_stdin_pipe_fifo1() {
// $ echo | stat -
// File: -
Expand All @@ -328,17 +340,26 @@ fn test_stdin_pipe_fifo1() {
.stdout_contains("fifo")
.stdout_contains("File: -")
.succeeded();

new_ucmd!()
.args(&["-L", "-"])
.set_stdin(std::process::Stdio::piped())
.run()
.no_stderr()
.stdout_contains("fifo")
.stdout_contains("File: -")
.succeeded();
}

#[cfg(unix)]
#[test]
#[cfg(disable_until_fixed)]
fn test_stdin_pipe_fifo2() {
// $ stat -
// File: -
// Size: 0 Blocks: 0 IO Block: 1024 character special file
new_ucmd!()
.arg("-")
.set_stdin(std::process::Stdio::null())
.run()
.no_stderr()
.stdout_contains("character special file")
Expand All @@ -348,7 +369,6 @@ fn test_stdin_pipe_fifo2() {

#[cfg(unix)]
#[test]
#[cfg(disable_until_fixed)]
fn test_stdin_redirect() {
// $ touch f && stat - < f
// File: -
Expand Down

0 comments on commit cba5205

Please sign in to comment.