diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 3a5941284..e7d665025 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1261,17 +1261,16 @@ fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> fn copy_on_write_linux(source: &Path, dest: &Path, mode: ReflinkMode) -> CopyResult<()> { debug_assert!(mode != ReflinkMode::Never); - let src_file = File::open(source).unwrap().as_raw_fd(); + let src_file = File::open(source).context(&*context_for(source, dest))?; let dst_file = OpenOptions::new() .write(true) .truncate(false) .create(true) .open(dest) - .unwrap() - .as_raw_fd(); + .context(&*context_for(source, dest))?; match mode { ReflinkMode::Always => unsafe { - let result = ficlone(dst_file, src_file as *const i32); + let result = ficlone(dst_file.as_raw_fd(), src_file.as_raw_fd() as *const i32); if result != 0 { return Err(format!( "failed to clone {:?} from {:?}: {}", @@ -1285,7 +1284,7 @@ fn copy_on_write_linux(source: &Path, dest: &Path, mode: ReflinkMode) -> CopyRes } }, ReflinkMode::Auto => unsafe { - let result = ficlone(dst_file, src_file as *const i32); + let result = ficlone(dst_file.as_raw_fd(), src_file.as_raw_fd() as *const i32); if result != 0 { fs::copy(source, dest).context(&*context_for(source, dest))?; } diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index bdab044c5..8cf6513cb 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -62,7 +62,6 @@ impl Number { impl FromStr for Number { type Err = String; - /// Tries to parse this string as a BigInt, or if that fails as an f64. fn from_str(mut s: &str) -> Result { if s.starts_with('+') { s = &s[1..]; @@ -71,10 +70,16 @@ impl FromStr for Number { match s.parse::() { Ok(n) => Ok(Number::BigInt(n)), Err(_) => match s.parse::() { - Ok(n) => Ok(Number::F64(n)), - Err(e) => Err(format!( - "seq: invalid floating point argument `{}`: {}", - s, e + Ok(value) if value.is_nan() => Err(format!( + "invalid 'not-a-number' argument: '{}'\nTry '{} --help' for more information.", + s, + executable!(), + )), + Ok(value) => Ok(Number::F64(value)), + Err(_) => Err(format!( + "invalid floating point argument: '{}'\nTry '{} --help' for more information.", + s, + executable!(), )), }, } @@ -136,13 +141,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let dec = slice.find('.').unwrap_or(len); largest_dec = len - dec; padding = dec; - match slice.parse() { - Ok(n) => n, - Err(s) => { - show_error!("{}", s); - return 1; - } - } + return_if_err!(1, slice.parse()) } else { Number::BigInt(BigInt::one()) }; @@ -152,30 +151,22 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let dec = slice.find('.').unwrap_or(len); largest_dec = cmp::max(largest_dec, len - dec); padding = cmp::max(padding, dec); - match slice.parse() { - Ok(n) => n, - Err(s) => { - show_error!("{}", s); - return 1; - } - } + return_if_err!(1, slice.parse()) } else { Number::BigInt(BigInt::one()) }; if increment.is_zero() { - show_error!("increment value: '{}'", numbers[1]); + show_error!( + "invalid Zero increment value: '{}'\nTry '{} --help' for more information.", + numbers[1], + executable!() + ); return 1; } let last = { let slice = numbers[numbers.len() - 1]; padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len())); - match slice.parse::() { - Ok(n) => n, - Err(s) => { - show_error!("{}", s); - return 1; - } - } + return_if_err!(1, slice.parse()) }; if largest_dec > 0 { largest_dec -= 1; diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index e995cc56c..c56e1ca57 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -7,6 +7,8 @@ use std::fs::set_permissions; #[cfg(not(windows))] use std::os::unix::fs; +#[cfg(target_os = "linux")] +use std::os::unix::fs::PermissionsExt; #[cfg(windows)] use std::os::windows::fs::symlink_file; @@ -1257,3 +1259,20 @@ fn test_cp_reflink_bad() { .fails() .stderr_contains("invalid argument"); } + +#[test] +#[cfg(target_os = "linux")] +fn test_cp_reflink_insufficient_permission() { + let (at, mut ucmd) = at_and_ucmd!(); + + at.make_file("unreadable") + .set_permissions(PermissionsExt::from_mode(0o000)) + .unwrap(); + + ucmd.arg("-r") + .arg("--reflink=auto") + .arg("unreadable") + .arg(TEST_EXISTING_FILE) + .fails() + .stderr_only("cp: 'unreadable' -> 'existing_file.txt': Permission denied (os error 13)"); +} diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index 98eb23598..459eeeb3a 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -1,5 +1,21 @@ use crate::common::util::*; +#[test] +fn test_rejects_nan() { + new_ucmd!() + .args(&["NaN"]) + .fails() + .stderr_only("seq: invalid 'not-a-number' argument: 'NaN'\nTry 'seq --help' for more information."); +} + +#[test] +fn test_rejects_non_floats() { + new_ucmd!() + .args(&["foo"]) + .fails() + .stderr_only("seq: invalid floating point argument: 'foo'\nTry 'seq --help' for more information."); +} + // ---- Tests for the big integer based path ---- #[test] diff --git a/tests/common/macros.rs b/tests/common/macros.rs index 81878bf1b..03d2051d0 100644 --- a/tests/common/macros.rs +++ b/tests/common/macros.rs @@ -50,14 +50,14 @@ macro_rules! new_ucmd { /// Convenience macro for acquiring a [`UCommand`] builder and a test path. /// /// Returns a tuple containing the following: -/// - an [`AsPath`] that points to a unique temporary test directory +/// - an [`AtPath`] that points to a unique temporary test directory /// - a [`UCommand`] builder for invoking the binary to be tested /// /// This macro is intended for quick, single-call tests. For more complex tests /// that require multiple invocations of the tested binary, see [`TestScenario`] /// /// [`UCommand`]: crate::tests::common::util::UCommand -/// [`AsPath`]: crate::tests::common::util::AsPath +/// [`AtPath`]: crate::tests::common::util::AtPath /// [`TestScenario]: crate::tests::common::util::TestScenario #[macro_export] macro_rules! at_and_ucmd {