From 1edd2bf3a89e5cf027bee026341d93d660a97cbb Mon Sep 17 00:00:00 2001 From: Jan Verbeek Date: Tue, 14 Sep 2021 15:07:57 +0200 Subject: [PATCH] Do not discard non-OS error messages --- .../cspell.dictionaries/jargon.wordlist.txt | 3 + src/uu/install/src/install.rs | 9 +-- src/uu/ls/src/ls.rs | 11 ++- src/uucore/src/lib/mods/error.rs | 76 ++++++++++++------- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/.vscode/cspell.dictionaries/jargon.wordlist.txt b/.vscode/cspell.dictionaries/jargon.wordlist.txt index cd1cc18b3..ed9e3d738 100644 --- a/.vscode/cspell.dictionaries/jargon.wordlist.txt +++ b/.vscode/cspell.dictionaries/jargon.wordlist.txt @@ -43,6 +43,9 @@ gibi gibibytes glob globbing +hardcode +hardcoded +hardcoding hardfloat hardlink hardlinks diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index a9f91f658..1c09f7f34 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -490,11 +490,10 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR return Err(InstallError::TargetDirIsntDir(target_dir.to_path_buf()).into()); } for sourcepath in files.iter() { - if !sourcepath.exists() { - let err = UIoError::new( - std::io::ErrorKind::NotFound, - format!("cannot stat {}", sourcepath.quote()), - ); + if let Err(err) = sourcepath + .metadata() + .map_err_context(|| format!("cannot stat {}", sourcepath.quote())) + { show!(err); continue; } diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index fad30157c..c5c65334e 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -42,7 +42,7 @@ use std::{ use term_grid::{Cell, Direction, Filling, Grid, GridOptions}; use uucore::{ display::Quotable, - error::{set_exit_code, FromIo, UError, UResult}, + error::{set_exit_code, UError, UResult}, }; use unicode_width::UnicodeWidthStr; @@ -1257,8 +1257,13 @@ fn list(locs: Vec<&Path>, config: Config) -> UResult<()> { let path_data = PathData::new(p, None, None, &config, true); if path_data.md().is_none() { - show!(std::io::ErrorKind::NotFound - .map_err_context(|| format!("cannot access {}", path_data.p_buf.quote()))); + // FIXME: Would be nice to use the actual error instead of hardcoding it + // Presumably other errors can happen too? + show_error!( + "cannot access {}: No such file or directory", + path_data.p_buf.quote() + ); + set_exit_code(1); // We found an error, no need to continue the execution continue; } diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 11ec91bdf..c04a0f2f1 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -393,34 +393,56 @@ impl Display for UIoError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { use std::io::ErrorKind::*; - let message; - let message = match self.inner.kind() { - NotFound => "No such file or directory", - PermissionDenied => "Permission denied", - ConnectionRefused => "Connection refused", - ConnectionReset => "Connection reset", - ConnectionAborted => "Connection aborted", - NotConnected => "Not connected", - AddrInUse => "Address in use", - AddrNotAvailable => "Address not available", - BrokenPipe => "Broken pipe", - AlreadyExists => "Already exists", - WouldBlock => "Would block", - InvalidInput => "Invalid input", - InvalidData => "Invalid data", - TimedOut => "Timed out", - WriteZero => "Write zero", - Interrupted => "Interrupted", - UnexpectedEof => "Unexpected end of file", - _ => { - // TODO: using `strip_errno()` causes the error message - // to not be capitalized. When the new error variants (https://github.com/rust-lang/rust/issues/86442) - // are stabilized, we should add them to the match statement. - message = strip_errno(&self.inner); - &message + let mut message; + let message = if self.inner.raw_os_error().is_some() { + // These are errors that come directly from the OS. + // We want to normalize their messages across systems, + // and we want to strip the "(os error X)" suffix. + match self.inner.kind() { + NotFound => "No such file or directory", + PermissionDenied => "Permission denied", + ConnectionRefused => "Connection refused", + ConnectionReset => "Connection reset", + ConnectionAborted => "Connection aborted", + NotConnected => "Not connected", + AddrInUse => "Address in use", + AddrNotAvailable => "Address not available", + BrokenPipe => "Broken pipe", + AlreadyExists => "Already exists", + WouldBlock => "Would block", + InvalidInput => "Invalid input", + InvalidData => "Invalid data", + TimedOut => "Timed out", + WriteZero => "Write zero", + Interrupted => "Interrupted", + UnexpectedEof => "Unexpected end of file", + _ => { + // TODO: When the new error variants + // (https://github.com/rust-lang/rust/issues/86442) + // are stabilized, we should add them to the match statement. + message = strip_errno(&self.inner); + capitalize(&mut message); + &message + } } + } else { + // These messages don't need as much normalization, and the above + // messages wouldn't always be a good substitute. + // For example, ErrorKind::NotFound doesn't necessarily mean it was + // a file that was not found. + // There are also errors with entirely custom messages. + message = self.inner.to_string(); + capitalize(&mut message); + &message }; - write!(f, "{}: {}", self.context, message,) + write!(f, "{}: {}", self.context, message) + } +} + +/// Capitalize the first character of an ASCII string. +fn capitalize(text: &mut str) { + if let Some(first) = text.get_mut(..1) { + first.make_ascii_uppercase(); } } @@ -428,7 +450,7 @@ impl Display for UIoError { pub fn strip_errno(err: &std::io::Error) -> String { let mut msg = err.to_string(); if let Some(pos) = msg.find(" (os error ") { - msg.drain(pos..); + msg.truncate(pos); } msg }