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
26 changes: 22 additions & 4 deletions src/find/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::io::{self, stderr, stdout, BufRead, BufReader, Write};
use std::path::PathBuf;
use std::rc::Rc;
use std::time::SystemTime;
use uucore::error;
use walkdir::WalkDir;

pub struct Config {
Expand Down Expand Up @@ -160,6 +161,8 @@ struct ParsedInfo {
/// <https://www.gnu.org/software/findutils/manual/html_node/find_html/Starting-points.html>
struct Files0Paths {
reader: Box<dyn BufRead>,
/// Kept so that read errors can be reported GNU-style with the offending file name.
name: String,
}

impl Files0Paths {
Expand All @@ -168,11 +171,19 @@ impl Files0Paths {
let reader: Box<dyn BufRead> = if name == "-" {
Box::new(BufReader::new(io::stdin()))
} else {
let file = std::fs::File::open(name)
.map_err(|e| format!("cannot open '{}' for reading: {}", name, e))?;
let file = std::fs::File::open(name).map_err(|e| {
format!(
"cannot open ‘{}’ for reading: {}",
name,
error::strip_errno(&e)
)
})?;
Box::new(BufReader::new(file))
};
Ok(Self { reader })
Ok(Self {
reader,
name: name.to_string(),
})
}
}

Expand All @@ -183,7 +194,14 @@ impl Iterator for Files0Paths {
loop {
let mut buffer = Vec::new();
match self.reader.read_until(0, &mut buffer) {
Err(e) => return Some(Err(e.into())),
Err(e) => {
return Some(Err(format!(
"‘{}’: read error: {}",
self.name,
error::strip_errno(&e)
)
.into()));
}
Ok(0) => return None,
Ok(_) => {}
}
Expand Down
20 changes: 20 additions & 0 deletions tests/test_find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1631,3 +1631,23 @@ fn find_exits_cleanly_on_broken_pipe() {
"find panicked instead of exiting cleanly on a broken pipe:\n{stderr}"
);
}

#[test]
#[cfg(target_os = "linux")]
fn files0_from_special_file_read_error() {
for path in &["/dev/vhost-net", "/dev/vhost-vsock"] {
if !Path::new(path).exists() {
continue;
}

let file_list_failure = ucmd().arg("-files0-from").arg(path).fails();

let error_output = file_list_failure.no_stdout().stderr_str();
assert!(
error_output.contains("read error")
|| (error_output.contains("cannot open")
&& error_output.contains("Permission denied")),
"unexpected stderr for {path}: {error_output}"
);
}
}
Loading