mirror of
https://github.com/uutils/coreutils
synced 2024-11-16 17:58:06 +00:00
Propagate all write and (most) flush errors
Signed-off-by: Hanif Ariffin <hanif.ariffin.4326@gmail.com>
This commit is contained in:
parent
f39b861469
commit
e35b93156a
1 changed files with 67 additions and 60 deletions
|
@ -1379,7 +1379,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"
|
||||||
|
@ -1443,7 +1444,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
|
||||||
|
@ -1451,7 +1452,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;
|
||||||
}
|
}
|
||||||
|
@ -1461,12 +1462,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(())
|
||||||
|
@ -1540,7 +1541,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![
|
||||||
|
@ -1570,7 +1571,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;
|
||||||
}
|
}
|
||||||
|
@ -1588,10 +1589,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
|
||||||
|
@ -1603,17 +1604,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> {
|
||||||
|
@ -1661,7 +1664,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
|
||||||
|
@ -1669,19 +1672,19 @@ 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.
|
||||||
|
|
||||||
if config.format == Format::Long {
|
if config.format == Format::Long {
|
||||||
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;
|
||||||
|
@ -1718,13 +1721,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 {
|
||||||
|
@ -1732,25 +1735,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 {
|
||||||
|
@ -1769,7 +1774,6 @@ fn get_block_size(md: &Metadata, config: &Config) -> u64 {
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
@ -1780,19 +1784,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 {
|
||||||
|
@ -1806,14 +1810,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`.
|
||||||
|
@ -1849,20 +1854,20 @@ 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!(
|
write!(
|
||||||
out,
|
out,
|
||||||
"{} ",
|
"{} ",
|
||||||
pad_left(&get_inode(md), padding.longest_inode_len),
|
pad_left(&get_inode(md), padding.longest_inode_len),
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
"{}{} {}",
|
"{}{} {}",
|
||||||
display_permissions(md, true),
|
display_permissions(md, true),
|
||||||
|
@ -1874,48 +1879,48 @@ fn display_item_long(
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
pad_left(&display_symlink_count(md), padding.longest_link_count_len),
|
pad_left(&display_symlink_count(md), padding.longest_link_count_len),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
if config.long.owner {
|
if config.long.owner {
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
" {}",
|
" {}",
|
||||||
pad_right(&display_uname(md, config), padding.longest_uname_len),
|
pad_right(&display_uname(md, config), padding.longest_uname_len),
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.long.group {
|
if config.long.group {
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
" {}",
|
" {}",
|
||||||
pad_right(&display_group(md, config), padding.longest_group_len),
|
pad_right(&display_group(md, config), padding.longest_group_len),
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.context {
|
if config.context {
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
" {}",
|
" {}",
|
||||||
pad_right(&item.security_context, padding.longest_context_len),
|
pad_right(&item.security_context, padding.longest_context_len),
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.longest_uname_len),
|
pad_right(&display_uname(md, config), padding.longest_uname_len),
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.longest_size_len),);
|
write!(out, " {}", pad_left(&size, padding.longest_size_len),)?;
|
||||||
}
|
}
|
||||||
SizeOrDeviceId::Device(major, minor) => {
|
SizeOrDeviceId::Device(major, minor) => {
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
" {}, {}",
|
" {}, {}",
|
||||||
pad_left(
|
pad_left(
|
||||||
|
@ -1936,19 +1941,19 @@ fn display_item_long(
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
padding.longest_minor_len,
|
padding.longest_minor_len,
|
||||||
),
|
),
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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.longest_inode_len),);
|
write!(out, "{} ", pad_left("?", padding.longest_inode_len),)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1985,7 +1990,7 @@ fn display_item_long(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
"{}{} {}",
|
"{}{} {}",
|
||||||
format_args!("{}?????????", leading_char),
|
format_args!("{}?????????", leading_char),
|
||||||
|
@ -1997,41 +2002,43 @@ fn display_item_long(
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
pad_left("?", padding.longest_link_count_len),
|
pad_left("?", padding.longest_link_count_len),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
if config.long.owner {
|
if config.long.owner {
|
||||||
let _ = write!(out, " {}", pad_right("?", padding.longest_uname_len));
|
write!(out, " {}", pad_right("?", padding.longest_uname_len))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.long.group {
|
if config.long.group {
|
||||||
let _ = write!(out, " {}", pad_right("?", padding.longest_group_len));
|
write!(out, " {}", pad_right("?", padding.longest_group_len))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.context {
|
if config.context {
|
||||||
let _ = write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
" {}",
|
" {}",
|
||||||
pad_right(&item.security_context, padding.longest_context_len)
|
pad_right(&item.security_context, padding.longest_context_len)
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.longest_uname_len));
|
write!(out, " {}", pad_right("?", padding.longest_uname_len))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.longest_size_len),
|
pad_left("?", padding.longest_size_len),
|
||||||
pad_left("?", date_len),
|
pad_left("?", date_len),
|
||||||
dfn,
|
dfn,
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
Loading…
Reference in a new issue