1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 13:07:46 +00:00

Merge pull request #3071 from hbina/hbina-ls-propagate-write-errors

ls: Propagate (almost) all write errors up
This commit is contained in:
Terts Diepraam 2022-02-18 08:41:00 +01:00 committed by GitHub
commit a3d52f3863
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1409,7 +1409,8 @@ impl PathData {
// if not, check if we can use Path metadata // if not, check if we can use Path metadata
match get_metadata(self.p_buf.as_path(), self.must_dereference) { match get_metadata(self.p_buf.as_path(), self.must_dereference) {
Err(err) => { Err(err) => {
let _ = out.flush(); // FIXME: A bit tricky to propagate the result here
out.flush().unwrap();
let errno = err.raw_os_error().unwrap_or(1i32); let errno = err.raw_os_error().unwrap_or(1i32);
// a bad fd will throw an error when dereferenced, // a bad fd will throw an error when dereferenced,
// but GNU will not throw an error until a bad fd "dir" // but GNU will not throw an error until a bad fd "dir"
@ -1473,7 +1474,7 @@ fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
sort_entries(&mut files, config, &mut out); sort_entries(&mut files, config, &mut out);
sort_entries(&mut dirs, config, &mut out); sort_entries(&mut dirs, config, &mut out);
display_items(&files, config, &mut out); display_items(&files, config, &mut out)?;
for (pos, path_data) in dirs.iter().enumerate() { for (pos, path_data) in dirs.iter().enumerate() {
// Do read_dir call here to match GNU semantics by printing // Do read_dir call here to match GNU semantics by printing
@ -1481,7 +1482,7 @@ fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
let read_dir = match fs::read_dir(&path_data.p_buf) { let read_dir = match fs::read_dir(&path_data.p_buf) {
Err(err) => { Err(err) => {
// flush stdout buffer before the error to preserve formatting and order // flush stdout buffer before the error to preserve formatting and order
let _ = out.flush(); out.flush()?;
show!(LsError::IOErrorContext(err, path_data.p_buf.clone())); show!(LsError::IOErrorContext(err, path_data.p_buf.clone()));
continue; continue;
} }
@ -1491,12 +1492,12 @@ fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
// Print dir heading - name... 'total' comes after error display // Print dir heading - name... 'total' comes after error display
if initial_locs_len > 1 || config.recursive { if initial_locs_len > 1 || config.recursive {
if pos.eq(&0usize) && files.is_empty() { if pos.eq(&0usize) && files.is_empty() {
let _ = writeln!(out, "{}:", path_data.p_buf.display()); writeln!(out, "{}:", path_data.p_buf.display())?;
} else { } else {
let _ = writeln!(out, "\n{}:", path_data.p_buf.display()); writeln!(out, "\n{}:", path_data.p_buf.display())?;
} }
} }
enter_directory(path_data, read_dir, config, &mut out); enter_directory(path_data, read_dir, config, &mut out)?;
} }
Ok(()) Ok(())
@ -1570,7 +1571,7 @@ fn enter_directory(
read_dir: ReadDir, read_dir: ReadDir,
config: &Config, config: &Config,
out: &mut BufWriter<Stdout>, out: &mut BufWriter<Stdout>,
) { ) -> UResult<()> {
// Create vec of entries with initial dot files // Create vec of entries with initial dot files
let mut entries: Vec<PathData> = if config.files == Files::All { let mut entries: Vec<PathData> = if config.files == Files::All {
vec![ vec![
@ -1600,7 +1601,7 @@ fn enter_directory(
let dir_entry = match raw_entry { let dir_entry = match raw_entry {
Ok(path) => path, Ok(path) => path,
Err(err) => { Err(err) => {
let _ = out.flush(); out.flush()?;
show!(LsError::IOError(err)); show!(LsError::IOError(err));
continue; continue;
} }
@ -1618,10 +1619,10 @@ fn enter_directory(
// Print total after any error display // Print total after any error display
if config.format == Format::Long { if config.format == Format::Long {
display_total(&entries, config, out); display_total(&entries, config, out)?;
} }
display_items(&entries, config, out); display_items(&entries, config, out)?;
if config.recursive { if config.recursive {
for e in entries for e in entries
@ -1633,17 +1634,19 @@ fn enter_directory(
{ {
match fs::read_dir(&e.p_buf) { match fs::read_dir(&e.p_buf) {
Err(err) => { Err(err) => {
let _ = out.flush(); out.flush()?;
show!(LsError::IOErrorContext(err, e.p_buf.clone())); show!(LsError::IOErrorContext(err, e.p_buf.clone()));
continue; continue;
} }
Ok(rd) => { Ok(rd) => {
let _ = writeln!(out, "\n{}:", e.p_buf.display()); writeln!(out, "\n{}:", e.p_buf.display())?;
enter_directory(e, rd, config, out); enter_directory(e, rd, config, out)?;
} }
} }
} }
} }
Ok(())
} }
fn get_metadata(p_buf: &Path, dereference: bool) -> std::io::Result<Metadata> { fn get_metadata(p_buf: &Path, dereference: bool) -> std::io::Result<Metadata> {
@ -1691,7 +1694,7 @@ fn pad_right(string: &str, count: usize) -> String {
format!("{:<width$}", string, width = count) format!("{:<width$}", string, width = count)
} }
fn display_total(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout>) { fn display_total(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout>) -> UResult<()> {
let mut total_size = 0; let mut total_size = 0;
for item in items { for item in items {
total_size += item total_size += item
@ -1699,10 +1702,11 @@ fn display_total(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout
.as_ref() .as_ref()
.map_or(0, |md| get_block_size(md, config)); .map_or(0, |md| get_block_size(md, config));
} }
let _ = writeln!(out, "total {}", display_size(total_size, config)); writeln!(out, "total {}", display_size(total_size, config))?;
Ok(())
} }
fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout>) { fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout>) -> UResult<()> {
// `-Z`, `--context`: // `-Z`, `--context`:
// Display the SELinux security context or '?' if none is found. When used with the `-l` // Display the SELinux security context or '?' if none is found. When used with the `-l`
// option, print the security context to the left of the size column. // option, print the security context to the left of the size column.
@ -1711,7 +1715,7 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout
let padding_collection = calculate_padding_collection(items, config, out); let padding_collection = calculate_padding_collection(items, config, out);
for item in items { for item in items {
display_item_long(item, &padding_collection, config, out); display_item_long(item, &padding_collection, config, out)?;
} }
} else { } else {
let mut longest_context_len = 1; let mut longest_context_len = 1;
@ -1748,13 +1752,13 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout
.into_iter(); .into_iter();
match config.format { match config.format {
Format::Columns => display_grid(names, config.width, Direction::TopToBottom, out), Format::Columns => display_grid(names, config.width, Direction::TopToBottom, out)?,
Format::Across => display_grid(names, config.width, Direction::LeftToRight, out), Format::Across => display_grid(names, config.width, Direction::LeftToRight, out)?,
Format::Commas => { Format::Commas => {
let mut current_col = 0; let mut current_col = 0;
let mut names = names; let mut names = names;
if let Some(name) = names.next() { if let Some(name) = names.next() {
let _ = write!(out, "{}", name.contents); write!(out, "{}", name.contents)?;
current_col = name.width as u16 + 2; current_col = name.width as u16 + 2;
} }
for name in names { for name in names {
@ -1762,25 +1766,27 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout
// If the width is 0 we print one single line // If the width is 0 we print one single line
if config.width != 0 && current_col + name_width + 1 > config.width { if config.width != 0 && current_col + name_width + 1 > config.width {
current_col = name_width + 2; current_col = name_width + 2;
let _ = write!(out, ",\n{}", name.contents); write!(out, ",\n{}", name.contents)?;
} else { } else {
current_col += name_width + 2; current_col += name_width + 2;
let _ = write!(out, ", {}", name.contents); write!(out, ", {}", name.contents)?;
} }
} }
// Current col is never zero again if names have been printed. // Current col is never zero again if names have been printed.
// So we print a newline. // So we print a newline.
if current_col > 0 { if current_col > 0 {
let _ = writeln!(out,); writeln!(out,)?;
} }
} }
_ => { _ => {
for name in names { for name in names {
let _ = writeln!(out, "{}", name.contents); writeln!(out, "{}", name.contents)?;
} }
} }
} };
} }
Ok(())
} }
fn get_block_size(md: &Metadata, config: &Config) -> u64 { fn get_block_size(md: &Metadata, config: &Config) -> u64 {
@ -1799,6 +1805,7 @@ fn get_block_size(md: &Metadata, config: &Config) -> u64 {
#[cfg(not(unix))] #[cfg(not(unix))]
{ {
// Silence linter warning about `config` being unused for windows.
let _ = config; let _ = config;
// no way to get block size for windows, fall-back to file size // no way to get block size for windows, fall-back to file size
md.len() md.len()
@ -1810,19 +1817,19 @@ fn display_grid(
width: u16, width: u16,
direction: Direction, direction: Direction,
out: &mut BufWriter<Stdout>, out: &mut BufWriter<Stdout>,
) { ) -> UResult<()> {
if width == 0 { if width == 0 {
// If the width is 0 we print one single line // If the width is 0 we print one single line
let mut printed_something = false; let mut printed_something = false;
for name in names { for name in names {
if printed_something { if printed_something {
let _ = write!(out, " "); write!(out, " ")?;
} }
printed_something = true; printed_something = true;
let _ = write!(out, "{}", name.contents); write!(out, "{}", name.contents)?;
} }
if printed_something { if printed_something {
let _ = writeln!(out); writeln!(out)?;
} }
} else { } else {
let mut grid = Grid::new(GridOptions { let mut grid = Grid::new(GridOptions {
@ -1836,14 +1843,15 @@ fn display_grid(
match grid.fit_into_width(width as usize) { match grid.fit_into_width(width as usize) {
Some(output) => { Some(output) => {
let _ = write!(out, "{}", output); write!(out, "{}", output)?;
} }
// Width is too small for the grid, so we fit it in one column // Width is too small for the grid, so we fit it in one column
None => { None => {
let _ = write!(out, "{}", grid.fit_into_columns(1)); write!(out, "{}", grid.fit_into_columns(1))?;
} }
} }
} }
Ok(())
} }
/// This writes to the BufWriter out a single string of the output of `ls -l`. /// This writes to the BufWriter out a single string of the output of `ls -l`.
@ -1879,16 +1887,16 @@ fn display_item_long(
padding: &PaddingCollection, padding: &PaddingCollection,
config: &Config, config: &Config,
out: &mut BufWriter<Stdout>, out: &mut BufWriter<Stdout>,
) { ) -> UResult<()> {
if let Some(md) = item.md(out) { if let Some(md) = item.md(out) {
#[cfg(unix)] #[cfg(unix)]
{ {
if config.inode { if config.inode {
let _ = write!(out, "{} ", pad_left(&get_inode(md), padding.inode),); write!(out, "{} ", pad_left(&get_inode(md), padding.inode))?;
} }
} }
let _ = write!( write!(
out, out,
"{}{} {}", "{}{} {}",
display_permissions(md, true), display_permissions(md, true),
@ -1899,49 +1907,49 @@ fn display_item_long(
} else { } else {
"" ""
}, },
pad_left(&display_symlink_count(md), padding.link_count), pad_left(&display_symlink_count(md), padding.link_count)
); )?;
if config.long.owner { if config.long.owner {
let _ = write!( write!(
out, out,
" {}", " {}",
pad_right(&display_uname(md, config), padding.uname), pad_right(&display_uname(md, config), padding.uname)
); )?;
} }
if config.long.group { if config.long.group {
let _ = write!( write!(
out, out,
" {}", " {}",
pad_right(&display_group(md, config), padding.group), pad_right(&display_group(md, config), padding.group)
); )?;
} }
if config.context { if config.context {
let _ = write!( write!(
out, out,
" {}", " {}",
pad_right(&item.security_context, padding.context), pad_right(&item.security_context, padding.context)
); )?;
} }
// Author is only different from owner on GNU/Hurd, so we reuse // Author is only different from owner on GNU/Hurd, so we reuse
// the owner, since GNU/Hurd is not currently supported by Rust. // the owner, since GNU/Hurd is not currently supported by Rust.
if config.long.author { if config.long.author {
let _ = write!( write!(
out, out,
" {}", " {}",
pad_right(&display_uname(md, config), padding.uname), pad_right(&display_uname(md, config), padding.uname)
); )?;
} }
match display_size_or_rdev(md, config) { match display_size_or_rdev(md, config) {
SizeOrDeviceId::Size(size) => { SizeOrDeviceId::Size(size) => {
let _ = write!(out, " {}", pad_left(&size, padding.size),); write!(out, " {}", pad_left(&size, padding.size))?;
} }
SizeOrDeviceId::Device(major, minor) => { SizeOrDeviceId::Device(major, minor) => {
let _ = write!( write!(
out, out,
" {}, {}", " {}, {}",
pad_left( pad_left(
@ -1962,19 +1970,19 @@ fn display_item_long(
#[cfg(unix)] #[cfg(unix)]
padding.minor, padding.minor,
), ),
); )?;
} }
}; };
let dfn = display_file_name(item, config, None, 0, out).contents; let dfn = display_file_name(item, config, None, 0, out).contents;
let _ = writeln!(out, " {} {}", display_date(md, config), dfn); writeln!(out, " {} {}", display_date(md, config), dfn)?;
} else { } else {
// this 'else' is expressly for the case of a dangling symlink/restricted file // this 'else' is expressly for the case of a dangling symlink/restricted file
#[cfg(unix)] #[cfg(unix)]
{ {
if config.inode { if config.inode {
let _ = write!(out, "{} ", pad_left("?", padding.inode),); write!(out, "{} ", pad_left("?", padding.inode))?;
} }
} }
@ -2011,7 +2019,7 @@ fn display_item_long(
} }
}; };
let _ = write!( write!(
out, out,
"{}{} {}", "{}{} {}",
format_args!("{}?????????", leading_char), format_args!("{}?????????", leading_char),
@ -2022,42 +2030,44 @@ fn display_item_long(
} else { } else {
"" ""
}, },
pad_left("?", padding.link_count), pad_left("?", padding.link_count)
); )?;
if config.long.owner { if config.long.owner {
let _ = write!(out, " {}", pad_right("?", padding.uname)); write!(out, " {}", pad_right("?", padding.uname))?;
} }
if config.long.group { if config.long.group {
let _ = write!(out, " {}", pad_right("?", padding.group)); write!(out, " {}", pad_right("?", padding.group))?;
} }
if config.context { if config.context {
let _ = write!( write!(
out, out,
" {}", " {}",
pad_right(&item.security_context, padding.context) pad_right(&item.security_context, padding.context)
); )?;
} }
// Author is only different from owner on GNU/Hurd, so we reuse // Author is only different from owner on GNU/Hurd, so we reuse
// the owner, since GNU/Hurd is not currently supported by Rust. // the owner, since GNU/Hurd is not currently supported by Rust.
if config.long.author { if config.long.author {
let _ = write!(out, " {}", pad_right("?", padding.uname)); write!(out, " {}", pad_right("?", padding.uname))?;
} }
let dfn = display_file_name(item, config, None, 0, out).contents; let dfn = display_file_name(item, config, None, 0, out).contents;
let date_len = 12; let date_len = 12;
let _ = writeln!( writeln!(
out, out,
" {} {} {}", " {} {} {}",
pad_left("?", padding.size), pad_left("?", padding.size),
pad_left("?", date_len), pad_left("?", date_len),
dfn, dfn,
); )?;
} }
Ok(())
} }
#[cfg(unix)] #[cfg(unix)]