From 6245029445fc781fd22f508ef28c8835230c57c1 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 8 Oct 2022 15:02:56 -0500 Subject: [PATCH 01/60] rm: rm3 now passes --- src/uu/rm/src/rm.rs | 154 +++++++++++++++++++++++++++------------ tests/by-util/test_rm.rs | 103 ++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 46 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 5406979f7..f3a4f2f4e 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -13,10 +13,8 @@ extern crate uucore; use clap::{crate_version, Arg, Command}; use remove_dir_all::remove_dir_all; use std::collections::VecDeque; -use std::fs; -use std::fs::File; -use std::io::ErrorKind; -use std::io::{stderr, stdin, BufRead, Write}; +use std::fs::{self, File, Metadata}; +use std::io::{stderr, stdin, BufRead, ErrorKind, Write}; use std::ops::BitOr; use std::path::{Path, PathBuf}; use uucore::display::Quotable; @@ -365,12 +363,7 @@ fn handle_dir(path: &Path, options: &Options) -> bool { } fn remove_dir(path: &Path, options: &Options) -> bool { - let response = if options.interactive == InteractiveMode::Always { - prompt_file(path, true) - } else { - true - }; - if response { + if prompt_file(path, options, true) { if let Ok(mut read_dir) = fs::read_dir(path) { if options.dir || options.recursive { if read_dir.next().is_none() { @@ -415,12 +408,7 @@ fn remove_dir(path: &Path, options: &Options) -> bool { } fn remove_file(path: &Path, options: &Options) -> bool { - let response = if options.interactive == InteractiveMode::Always { - prompt_file(path, false) - } else { - true - }; - if response && prompt_write_protected(path, false, options) { + if prompt_file(path, options, false) { match fs::remove_file(path) { Ok(_) => { if options.verbose { @@ -442,46 +430,122 @@ fn remove_file(path: &Path, options: &Options) -> bool { false } -fn prompt_write_protected(path: &Path, is_dir: bool, options: &Options) -> bool { +fn prompt_file(path: &Path, options: &Options, is_dir: bool) -> bool { + // If interactive is Never we never want to send prompts if options.interactive == InteractiveMode::Never { return true; } - match File::open(path) { - Ok(_) => true, - Err(err) => { - if err.kind() == ErrorKind::PermissionDenied { - if is_dir { - prompt(&(format!("rm: remove write-protected directory {}? ", path.quote()))) - } else { - if fs::metadata(path).unwrap().len() == 0 { - return prompt( - &(format!( - "rm: remove write-protected regular empty file {}? ", - path.quote() - )), - ); + // If interactive is Always we want to check if the file is symlink to prompt the right message + if options.interactive == InteractiveMode::Always { + if let Ok(metadata) = fs::symlink_metadata(path) { + if metadata.is_symlink() { + return prompt(&(format!("remove symbolic link {}? ", path.quote()))); + } + } + } + if is_dir { + // We can't use metadata.permissions.readonly for directories because it only works on files + // So we have to handle wether a directory is writable on not manually + if let Ok(metadata) = fs::metadata(path) { + handle_writable_directory(path, options, &metadata) + } else { + true + } + } else { + // File::open(path) doesn't open the file in write mode so we need to use file options to open it in also write mode to check if it can written too + match File::options().read(true).write(true).open(path) { + Ok(file) => { + if let Ok(metadata) = file.metadata() { + if metadata.permissions().readonly() { + if metadata.len() == 0 { + prompt( + &(format!( + "remove write-protected regular empty file {}? ", + path.quote() + )), + ) + } else { + prompt( + &(format!( + "remove write-protected regular file {}? ", + path.quote() + )), + ) + } + } else if options.interactive == InteractiveMode::Always { + if metadata.len() == 0 { + prompt(&(format!("remove regular empty file {}? ", path.quote()))) + } else { + prompt(&(format!("remove file {}? ", path.quote()))) + } + } else { + true } - prompt(&(format!("rm: remove write-protected regular file {}? ", path.quote()))) + } else { + true + } + } + Err(err) => { + if err.kind() == ErrorKind::PermissionDenied { + if let Ok(metadata) = fs::metadata(path) { + if metadata.len() == 0 { + prompt( + &(format!( + "remove write-protected regular empty file {}? ", + path.quote() + )), + ) + } else { + prompt( + &(format!( + "remove write-protected regular file {}? ", + path.quote() + )), + ) + } + } else { + prompt(&(format!("remove write-protected regular file {}? ", path.quote()))) + } + } else { + true } - } else { - true } } } } -fn prompt_descend(path: &Path) -> bool { - prompt(&(format!("rm: descend into directory {}? ", path.quote()))) +// For directories finding if they are writable or not is a hassle. In Unix we can use the built-in rust crate to to check mode bits. But other os don't have something similar afaik +#[cfg(unix)] +fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { + use std::os::unix::fs::PermissionsExt; + let mode = metadata.permissions().mode(); + let user_write_permission = (mode & 0b1_1100_0000) >> 6; + let user_writable = !matches!(user_write_permission, 0o0 | 0o1 | 0o4 | 0o5); + if !user_writable { + prompt(&(format!("remove write-protected directory {}? ", path.quote()))) + } else if options.interactive == InteractiveMode::Always { + prompt(&(format!("remove directory {}? ", path.quote()))) + } else { + true + } } -fn prompt_file(path: &Path, is_dir: bool) -> bool { - if is_dir { - prompt(&(format!("rm: remove directory {}? ", path.quote()))) +// I have this here for completeness but it will always return "remove directory {}" because metadata.permissions().readonly() only works for file not directories +#[cfg(not(unix))] +fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { + if metadata.permissions().readonly() { + prompt(&(format!("remove write-protected directory {}? ", path.quote()))) + } else if options.interactive == InteractiveMode::Always { + prompt(&(format!("remove directory {}? ", path.quote()))) } else { - prompt(&(format!("rm: remove file {}? ", path.quote()))) + true } } +fn prompt_descend(path: &Path) -> bool { + prompt(&(format!("descend into directory {}? ", path.quote()))) +} + fn normalize(path: &Path) -> PathBuf { // copied from https://github.com/rust-lang/cargo/blob/2e4cfc2b7d43328b207879228a2ca7d427d188bb/src/cargo/util/paths.rs#L65-L90 // both projects are MIT https://github.com/rust-lang/cargo/blob/master/LICENSE-MIT @@ -491,7 +555,7 @@ fn normalize(path: &Path) -> PathBuf { } fn prompt(msg: &str) -> bool { - let _ = stderr().write_all(msg.as_bytes()); + let _ = stderr().write_all(format!("{}: {}", uucore::util_name(), msg).as_bytes()); let _ = stderr().flush(); let mut buf = Vec::new(); @@ -505,15 +569,13 @@ fn prompt(msg: &str) -> bool { } #[cfg(not(windows))] -fn is_symlink_dir(_metadata: &fs::Metadata) -> bool { +fn is_symlink_dir(_metadata: &Metadata) -> bool { false } #[cfg(windows)] -use std::os::windows::prelude::MetadataExt; - -#[cfg(windows)] -fn is_symlink_dir(metadata: &fs::Metadata) -> bool { +fn is_symlink_dir(metadata: &Metadata) -> bool { + use std::os::windows::prelude::MetadataExt; use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; metadata.file_type().is_symlink() diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index b600c2090..60b1f12b8 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -400,6 +400,109 @@ fn test_rm_descend_directory() { assert!(!at.file_exists(file_2)); } +#[cfg(feature = "chmod")] +#[test] +fn test_rm_prompts() { + use std::io::Write; + use std::process::Child; + + // Needed for talking with stdin on platforms where CRLF or LF matters + const END_OF_LINE: &str = if cfg!(windows) { "\r\n" } else { "\n" }; + + let mut answers = vec![ + "rm: descend into directory 'a'?", + "rm: remove write-protected regular empty file 'a/empty-no-write'?", + "rm: remove symbolic link 'a/slink'?", + "rm: remove symbolic link 'a/slink-dot'?", + "rm: remove write-protected regular file 'a/f-no-write'?", + "rm: remove regular empty file 'a/empty'?", + "rm: remove directory 'a/b'?", + "rm: remove write-protected directory 'a/b-no-write'?", + "rm: remove directory 'a'?", + ]; + + answers.sort(); + + let yes = format!("y{}", END_OF_LINE); + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.mkdir("a/"); + + let file_1 = "a/empty"; + let file_2 = "a/empty-no-write"; + let file_3 = "a/f-no-write"; + + at.touch(file_1); + at.touch(file_2); + at.make_file(file_3) + .write_all(b"not-empty") + .expect("Couldn't write to a/f-no-write"); + + at.symlink_dir("a/empty-f", "a/slink"); + at.symlink_dir(".", "a/slink-dot"); + + let dir_1 = "a/b/"; + let dir_2 = "a/b-no-write/"; + + at.mkdir(dir_1); + at.mkdir(dir_2); + + scene + .ccmd("chmod") + .arg("u-w") + .arg(file_3) + .arg(dir_2) + .arg(file_2) + .succeeds(); + + let mut child: Child = scene.ucmd().arg("-ri").arg("a").run_no_wait(); + + let mut child_stdin = child.stdin.take().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + + let output = child.wait_with_output().unwrap(); + + let mut trimmed_output = Vec::new(); + for string in String::from_utf8(output.stderr) + .expect("Couldn't convert output.stderr to string") + .split("rm: ") + { + if !string.is_empty() { + let trimmed_string = format!("rm: {}", string).trim().to_string(); + trimmed_output.push(trimmed_string); + } + } + + trimmed_output.sort(); + + assert!(trimmed_output.len() == answers.len()); + + for (i, checking_string) in trimmed_output.iter().enumerate() { + assert!(checking_string == answers[i]); + } + + assert!(!at.dir_exists("a")); +} + #[test] #[ignore = "issue #3722"] fn test_rm_directory_rights_rm1() { From 30adc8e037b3cdf6f5bce61c17a4be489b4e18f5 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 8 Oct 2022 15:22:09 -0500 Subject: [PATCH 02/60] Added windows version of handle_writable_directory --- src/uu/rm/src/rm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index f3a4f2f4e..fd3dd4a5c 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -530,7 +530,23 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata } } +// For windows we can use windows metadata trait and file attirubtes to see if a directory is readonly +#[cfg(windows)] +fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { + use std::os::windows::prelude::MetadataExt; + use winapi::um::winnt::FILE_ATTRIBUTE_READONLY; + let user_writable = (metadata.file_attributes() & FILE_ATTRIBUTE_READONLY) != 0; + if !user_writable { + prompt(&(format!("remove write-protected directory {}? ", path.quote()))) + } else if options.interactive == InteractiveMode::Always { + prompt(&(format!("remove directory {}? ", path.quote()))) + } else { + true + } +} + // I have this here for completeness but it will always return "remove directory {}" because metadata.permissions().readonly() only works for file not directories +#[cfg(not(windows))] #[cfg(not(unix))] fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { if metadata.permissions().readonly() { From 1f50df2af6f6c2726205cfdbfde96e0f9c40efc7 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 8 Oct 2022 16:47:27 -0500 Subject: [PATCH 03/60] Fixed spelling error --- src/uu/rm/src/rm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index fd3dd4a5c..bd8cb7dcb 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -530,7 +530,7 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata } } -// For windows we can use windows metadata trait and file attirubtes to see if a directory is readonly +// For windows we can use windows metadata trait and file attributes to see if a directory is readonly #[cfg(windows)] fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { use std::os::windows::prelude::MetadataExt; From 6856ce0bf40f6c8376592d72294473d2494e361c Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 8 Oct 2022 16:51:14 -0500 Subject: [PATCH 04/60] Fixed handle_writable_directory on windows --- src/uu/rm/src/rm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index bd8cb7dcb..a72a88393 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -535,8 +535,8 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { use std::os::windows::prelude::MetadataExt; use winapi::um::winnt::FILE_ATTRIBUTE_READONLY; - let user_writable = (metadata.file_attributes() & FILE_ATTRIBUTE_READONLY) != 0; - if !user_writable { + let not_user_writable = (metadata.file_attributes() & FILE_ATTRIBUTE_READONLY) != 0; + if not_user_writable { prompt(&(format!("remove write-protected directory {}? ", path.quote()))) } else if options.interactive == InteractiveMode::Always { prompt(&(format!("remove directory {}? ", path.quote()))) From 50d2948aa1bc25cb8f463d5964517c23f8ecde83 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sun, 9 Oct 2022 17:24:36 -0500 Subject: [PATCH 05/60] Fixed rm --force argument not forcing prompt to not show up --- src/uu/rm/src/rm.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index a72a88393..b5adcf9e8 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -98,7 +98,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = Options { force, interactive: { - if matches.contains_id(OPT_PROMPT) { + if force { + InteractiveMode::Never + } else if matches.contains_id(OPT_PROMPT) { InteractiveMode::Always } else if matches.contains_id(OPT_PROMPT_MORE) { InteractiveMode::Once From 3c39a57da0a32ec20beb4a03be31a09136e4b18f Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Mon, 10 Oct 2022 12:43:01 -0500 Subject: [PATCH 06/60] Check force position in rm --- src/uu/rm/src/rm.rs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index b5adcf9e8..576094d5d 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -88,17 +88,38 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(|v| v.map(ToString::to_string).collect()) .unwrap_or_default(); - let force = matches.contains_id(OPT_FORCE); + let force_index_option = matches.index_of(OPT_FORCE); - if files.is_empty() && !force { + // If -f(--force) is before any -i (or variants) we want prompts else no prompts + let force_first: bool = { + if let Some(force_index) = force_index_option { + let prompt_index_option = matches.index_of(OPT_PROMPT); + let prompt_more_index_option = matches.index_of(OPT_PROMPT_MORE); + let interactive_index_option = matches.index_of(OPT_INTERACTIVE); + + if let Some(prompt_index) = prompt_index_option { + prompt_index > force_index + } else if let Some(prompt_more_index_index) = prompt_more_index_option { + prompt_more_index_index > force_index + } else if let Some(interactive_index) = interactive_index_option { + interactive_index > force_index + } else { + true + } + } else { + true + } + }; + + if files.is_empty() && force_index_option.is_none() { // Still check by hand and not use clap // Because "rm -f" is a thing return Err(UUsageError::new(1, "missing operand")); } else { let options = Options { - force, + force: force_index_option.is_some(), interactive: { - if force { + if force_index_option.is_some() && !force_first { InteractiveMode::Never } else if matches.contains_id(OPT_PROMPT) { InteractiveMode::Always From 70bf4f36a04a3cb6200b787494a4857191015613 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Mon, 10 Oct 2022 13:48:34 -0500 Subject: [PATCH 07/60] Added test to check rm force prompts order --- tests/by-util/test_rm.rs | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 60b1f12b8..dcf85f4d1 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -503,6 +503,48 @@ fn test_rm_prompts() { assert!(!at.dir_exists("a")); } +#[test] +fn test_rm_force_prompts_order() { + use std::io::Write; + use std::process::Child; + + // Needed for talking with stdin on platforms where CRLF or LF matters + const END_OF_LINE: &str = if cfg!(windows) { "\r\n" } else { "\n" }; + + let yes = format!("y{}", END_OF_LINE); + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let empty_file = "empty"; + + at.touch(empty_file); + + // This should cause rm to prompt to remove regular empty file + let mut child: Child = scene.ucmd().arg("-fi").arg(empty_file).run_no_wait(); + + let mut child_stdin = child.stdin.take().unwrap(); + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + + let output = child.wait_with_output().unwrap(); + let string_output = + String::from_utf8(output.stderr).expect("Couldn't convert output.stderr to string"); + assert!(string_output.trim() == String::from("rm: remove regular empty file 'empty'?")); + assert!(!at.file_exists(empty_file)); + + at.touch(empty_file); + + // This should not cause rm to prompt to remove regular empty file + scene + .ucmd() + .arg("-if") + .arg(empty_file) + .succeeds() + .no_stderr(); + assert!(!at.file_exists(empty_file)); +} + #[test] #[ignore = "issue #3722"] fn test_rm_directory_rights_rm1() { From 0507270f90d32698d5bfd86bcf2e109c6c6c0e1a Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Mon, 10 Oct 2022 13:52:05 -0500 Subject: [PATCH 08/60] Clippy is going to be the death of me --- tests/by-util/test_rm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index dcf85f4d1..98273fedd 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -530,7 +530,7 @@ fn test_rm_force_prompts_order() { let output = child.wait_with_output().unwrap(); let string_output = String::from_utf8(output.stderr).expect("Couldn't convert output.stderr to string"); - assert!(string_output.trim() == String::from("rm: remove regular empty file 'empty'?")); + assert!(string_output.trim() == "rm: remove regular empty file 'empty'?"); assert!(!at.file_exists(empty_file)); at.touch(empty_file); From 3a1098489e6a7b1b71b77ca8c7e6b4a35af3363e Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Mon, 10 Oct 2022 15:01:17 -0500 Subject: [PATCH 09/60] Small fix --- src/uu/rm/src/rm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 576094d5d..f83c09031 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -104,7 +104,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } else if let Some(interactive_index) = interactive_index_option { interactive_index > force_index } else { - true + false } } else { true From 355136936fc158dd0cfdad8c109d54bc28d0434a Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Tue, 11 Oct 2022 15:45:20 -0500 Subject: [PATCH 10/60] Fixed force rm --- src/uu/rm/src/rm.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index f83c09031..2143bb8e3 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -91,23 +91,33 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let force_index_option = matches.index_of(OPT_FORCE); // If -f(--force) is before any -i (or variants) we want prompts else no prompts - let force_first: bool = { + let force_prompt_never: bool = { if let Some(force_index) = force_index_option { let prompt_index_option = matches.index_of(OPT_PROMPT); let prompt_more_index_option = matches.index_of(OPT_PROMPT_MORE); let interactive_index_option = matches.index_of(OPT_INTERACTIVE); + let mut result = true; + if let Some(prompt_index) = prompt_index_option { - prompt_index > force_index - } else if let Some(prompt_more_index_index) = prompt_more_index_option { - prompt_more_index_index > force_index - } else if let Some(interactive_index) = interactive_index_option { - interactive_index > force_index - } else { - false + if result { + result = prompt_index <= force_index; + } } + if let Some(prompt_more_index_index) = prompt_more_index_option { + if result { + result = prompt_more_index_index <= force_index; + } + } + if let Some(interactive_index) = interactive_index_option { + if result { + result = interactive_index <= force_index; + } + } + + result } else { - true + false } }; @@ -119,7 +129,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = Options { force: force_index_option.is_some(), interactive: { - if force_index_option.is_some() && !force_first { + if force_index_option.is_some() && force_prompt_never { InteractiveMode::Never } else if matches.contains_id(OPT_PROMPT) { InteractiveMode::Always From e11dd50eb4f3572a52b5c92dae76b977349e8998 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Wed, 12 Oct 2022 16:54:38 -0500 Subject: [PATCH 11/60] Added comments --- src/uu/rm/src/rm.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 2143bb8e3..a8932b7f5 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -99,16 +99,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let mut result = true; + // if we have rm -i -f if let Some(prompt_index) = prompt_index_option { if result { result = prompt_index <= force_index; } } + // if we have rm -I -f if let Some(prompt_more_index_index) = prompt_more_index_option { if result { result = prompt_more_index_index <= force_index; } } + // if we have rm --interactive -f if let Some(interactive_index) = interactive_index_option { if result { result = interactive_index <= force_index; From a3f35a726cb48cc65189ce968b6e64cd16b44c6b Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Wed, 12 Oct 2022 17:31:28 -0500 Subject: [PATCH 12/60] Add override for prompting --- src/uu/rm/src/rm.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index a8932b7f5..ead7a63b6 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -194,12 +194,13 @@ pub fn uu_app<'a>() -> Command<'a> { .arg( Arg::new(OPT_PROMPT) .short('i') - .help("prompt before every removal"), + .help("prompt before every removal") + .overrides_with_all(&[OPT_PROMPT_MORE, OPT_INTERACTIVE]), ) .arg(Arg::new(OPT_PROMPT_MORE).short('I').help( "prompt once before removing more than three files, or when removing recursively. \ Less intrusive than -i, while still giving some protection against most mistakes", - )) + ).overrides_with_all(&[OPT_PROMPT, OPT_INTERACTIVE])) .arg( Arg::new(OPT_INTERACTIVE) .long(OPT_INTERACTIVE) @@ -208,7 +209,8 @@ pub fn uu_app<'a>() -> Command<'a> { prompts always", ) .value_name("WHEN") - .takes_value(true), + .takes_value(true) + .overrides_with_all(&[OPT_PROMPT, OPT_PROMPT_MORE]), ) .arg( Arg::new(OPT_ONE_FILE_SYSTEM) From fddc8c9d9d6896ceb91932cdb273013aa07b05d8 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Thu, 13 Oct 2022 17:22:59 -0500 Subject: [PATCH 13/60] More readable unix write permissions for directory using libc --- src/uu/rm/Cargo.toml | 3 +++ src/uu/rm/src/rm.rs | 8 +++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/uu/rm/Cargo.toml b/src/uu/rm/Cargo.toml index e992d86d1..3196c71ce 100644 --- a/src/uu/rm/Cargo.toml +++ b/src/uu/rm/Cargo.toml @@ -20,6 +20,9 @@ walkdir = "2.2" remove_dir_all = "0.7.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +[target.'cfg(unix)'.dependencies] +libc = "0.2.135" + [target.'cfg(windows)'.dependencies] winapi = { version="0.3", features=[] } diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index ead7a63b6..fa4d8cc35 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -557,8 +557,8 @@ fn prompt_file(path: &Path, options: &Options, is_dir: bool) -> bool { fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { use std::os::unix::fs::PermissionsExt; let mode = metadata.permissions().mode(); - let user_write_permission = (mode & 0b1_1100_0000) >> 6; - let user_writable = !matches!(user_write_permission, 0o0 | 0o1 | 0o4 | 0o5); + // Check if directory has user write permissions + let user_writable = (mode & libc::S_IWUSR) != 0; if !user_writable { prompt(&(format!("remove write-protected directory {}? ", path.quote()))) } else if options.interactive == InteractiveMode::Always { @@ -587,9 +587,7 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata #[cfg(not(windows))] #[cfg(not(unix))] fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { - if metadata.permissions().readonly() { - prompt(&(format!("remove write-protected directory {}? ", path.quote()))) - } else if options.interactive == InteractiveMode::Always { + if options.interactive == InteractiveMode::Always { prompt(&(format!("remove directory {}? ", path.quote()))) } else { true From e89d9d091da44a0e15653c0acf0b4341680004b1 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Thu, 13 Oct 2022 17:37:11 -0500 Subject: [PATCH 14/60] Forgot .lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 097df2a5e..8700897d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2691,6 +2691,7 @@ name = "uu_rm" version = "0.0.16" dependencies = [ "clap", + "libc", "remove_dir_all 0.7.0", "uucore", "walkdir", From 21b066a58e38b808953919636819aaf0f18ff740 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Thu, 13 Oct 2022 17:40:27 -0500 Subject: [PATCH 15/60] Why is S_IWUSR showing up as a u16 on macos --- src/uu/rm/src/rm.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index fa4d8cc35..b17ea2d63 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -558,7 +558,8 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata use std::os::unix::fs::PermissionsExt; let mode = metadata.permissions().mode(); // Check if directory has user write permissions - let user_writable = (mode & libc::S_IWUSR) != 0; + // Why is S_IWUSR showing up as a u16 on macos? + let user_writable = (mode & (libc::S_IWUSR as u32)) != 0; if !user_writable { prompt(&(format!("remove write-protected directory {}? ", path.quote()))) } else if options.interactive == InteractiveMode::Always { From 430652193be939b9dbdd2487fa1c951da2d67af3 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 15 Oct 2022 15:08:28 -0500 Subject: [PATCH 16/60] Fixed merge conflicts --- Cargo.lock | 2 +- src/uu/rm/src/rm.rs | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 763d24fa9..149099e8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2713,7 +2713,7 @@ name = "uu_rm" version = "0.0.16" dependencies = [ "clap 4.0.14", - "libc" + "libc", "remove_dir_all 0.7.0", "uucore", "walkdir", diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index f94c4ce46..b45938a86 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -196,11 +196,14 @@ pub fn uu_app() -> Command { .overrides_with_all(&[OPT_PROMPT_MORE, OPT_INTERACTIVE]) .action(ArgAction::SetTrue), ) - .arg(Arg::new(OPT_PROMPT_MORE).short('I').help( - "prompt once before removing more than three files, or when removing recursively. \ - Less intrusive than -i, while still giving some protection against most mistakes", - ).overrides_with_all(&[OPT_PROMPT, OPT_INTERACTIVE]) - ).action(ArgAction::SetTrue)) + .arg( + Arg::new(OPT_PROMPT_MORE) + .short('I') + .help("prompt once before removing more than three files, or when removing recursively. \ + Less intrusive than -i, while still giving some protection against most mistakes") + .overrides_with_all(&[OPT_PROMPT, OPT_INTERACTIVE]) + .action(ArgAction::SetTrue), + ) .arg( Arg::new(OPT_INTERACTIVE) .long(OPT_INTERACTIVE) @@ -208,7 +211,7 @@ pub fn uu_app() -> Command { "prompt according to WHEN: never, once (-I), or always (-i). Without WHEN, \ prompts always", ) - .value_name("WHEN"), + .value_name("WHEN") .overrides_with_all(&[OPT_PROMPT, OPT_PROMPT_MORE]), ) .arg( From 1c507c6739f7ce3bc3efa82ca23cc8203e185e86 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 15 Oct 2022 17:39:10 -0500 Subject: [PATCH 17/60] Updated to clap4 --- src/uu/rm/src/rm.rs | 70 ++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index b45938a86..8898f546f 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -10,7 +10,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, ArgAction, Command}; +use clap::{crate_version, Arg, ArgAction, Command, parser::ValueSource}; use remove_dir_all::remove_dir_all; use std::collections::VecDeque; use std::fs::{self, File, Metadata}; @@ -85,51 +85,61 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(|v| v.map(ToString::to_string).collect()) .unwrap_or_default(); - let force_index_option = matches.index_of(OPT_FORCE); + let force_flag = matches.get_flag(OPT_FORCE); // If -f(--force) is before any -i (or variants) we want prompts else no prompts - let force_prompt_never: bool = { - if let Some(force_index) = force_index_option { - let prompt_index_option = matches.index_of(OPT_PROMPT); - let prompt_more_index_option = matches.index_of(OPT_PROMPT_MORE); - let interactive_index_option = matches.index_of(OPT_INTERACTIVE); - - let mut result = true; - - // if we have rm -i -f - if let Some(prompt_index) = prompt_index_option { - if result { - result = prompt_index <= force_index; + let force_prompt_never: bool = if force_flag { + if matches.value_source(OPT_FORCE) == Some(ValueSource::CommandLine) { + if let Some(force_index) = matches.index_of(OPT_FORCE) { + let mut result = true; + + // if we have rm -i -f + if matches.value_source(OPT_PROMPT) == Some(ValueSource::CommandLine) { + if let Some(prompt_index) = matches.index_of(OPT_PROMPT) { + if result { + result = prompt_index <= force_index; + } + } } - } - // if we have rm -I -f - if let Some(prompt_more_index_index) = prompt_more_index_option { - if result { - result = prompt_more_index_index <= force_index; + + // if we have rm -I -f + if matches.value_source(OPT_PROMPT_MORE) == Some(ValueSource::CommandLine) { + if let Some(prompt_more_index_index) = matches.index_of(OPT_PROMPT_MORE) { + if result { + result = prompt_more_index_index <= force_index; + } + } } - } - // if we have rm --interactive -f - if let Some(interactive_index) = interactive_index_option { - if result { - result = interactive_index <= force_index; - } - } - result + // if we have rm --interactive -f + if matches.value_source(OPT_INTERACTIVE) == Some(ValueSource::CommandLine) { + if let Some(interactive_index) = matches.index_of(OPT_INTERACTIVE) { + if result { + result = interactive_index <= force_index; + } + } + } + + result + } else { + false + } } else { false } + } else { + false }; - if files.is_empty() && force_index_option.is_none() { + if files.is_empty() && !force_flag { // Still check by hand and not use clap // Because "rm -f" is a thing return Err(UUsageError::new(1, "missing operand")); } else { let options = Options { - force: force_index_option.is_some(), + force: force_flag, interactive: { - if force_index_option.is_some() && force_prompt_never { + if force_flag && force_prompt_never { InteractiveMode::Never } else if matches.get_flag(OPT_PROMPT) { InteractiveMode::Always From b3b90e453cc9cc9e1b25cb6eac71562480da5fbe Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 15 Oct 2022 17:41:11 -0500 Subject: [PATCH 18/60] Forgot fmt again --- src/uu/rm/src/rm.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 8898f546f..db16cda11 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -10,7 +10,7 @@ #[macro_use] extern crate uucore; -use clap::{crate_version, Arg, ArgAction, Command, parser::ValueSource}; +use clap::{crate_version, parser::ValueSource, Arg, ArgAction, Command}; use remove_dir_all::remove_dir_all; use std::collections::VecDeque; use std::fs::{self, File, Metadata}; @@ -92,7 +92,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if matches.value_source(OPT_FORCE) == Some(ValueSource::CommandLine) { if let Some(force_index) = matches.index_of(OPT_FORCE) { let mut result = true; - + // if we have rm -i -f if matches.value_source(OPT_PROMPT) == Some(ValueSource::CommandLine) { if let Some(prompt_index) = matches.index_of(OPT_PROMPT) { @@ -101,14 +101,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } } - + // if we have rm -I -f if matches.value_source(OPT_PROMPT_MORE) == Some(ValueSource::CommandLine) { if let Some(prompt_more_index_index) = matches.index_of(OPT_PROMPT_MORE) { if result { result = prompt_more_index_index <= force_index; } - } + } } // if we have rm --interactive -f @@ -117,9 +117,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if result { result = interactive_index <= force_index; } - } + } } - + result } else { false From b612ce5cd7e1ce2b6503dd2e1f4a757af708f608 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sun, 16 Oct 2022 10:57:12 -0500 Subject: [PATCH 19/60] Cleaner force_prompt_never --- src/uu/rm/src/rm.rs | 45 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index db16cda11..190298aa6 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -88,47 +88,18 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let force_flag = matches.get_flag(OPT_FORCE); // If -f(--force) is before any -i (or variants) we want prompts else no prompts - let force_prompt_never: bool = if force_flag { + let force_prompt_never: bool = force_flag && { if matches.value_source(OPT_FORCE) == Some(ValueSource::CommandLine) { - if let Some(force_index) = matches.index_of(OPT_FORCE) { - let mut result = true; - - // if we have rm -i -f - if matches.value_source(OPT_PROMPT) == Some(ValueSource::CommandLine) { - if let Some(prompt_index) = matches.index_of(OPT_PROMPT) { - if result { - result = prompt_index <= force_index; - } - } - } - - // if we have rm -I -f - if matches.value_source(OPT_PROMPT_MORE) == Some(ValueSource::CommandLine) { - if let Some(prompt_more_index_index) = matches.index_of(OPT_PROMPT_MORE) { - if result { - result = prompt_more_index_index <= force_index; - } - } - } - - // if we have rm --interactive -f - if matches.value_source(OPT_INTERACTIVE) == Some(ValueSource::CommandLine) { - if let Some(interactive_index) = matches.index_of(OPT_INTERACTIVE) { - if result { - result = interactive_index <= force_index; - } - } - } - - result - } else { - false - } + let force_index = matches.index_of(OPT_FORCE).unwrap_or(0); + [OPT_PROMPT, OPT_PROMPT_MORE, OPT_INTERACTIVE] + .iter() + .any(|opt| { + matches.value_source(opt) == Some(ValueSource::CommandLine) + && matches.index_of(opt).unwrap_or(0) < force_index + }) } else { false } - } else { - false }; if files.is_empty() && !force_flag { From 03578a7acae1c9434508c13a4a3ccd16bab82f46 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sun, 16 Oct 2022 13:14:17 -0500 Subject: [PATCH 20/60] Fixed invert issue --- src/uu/rm/src/rm.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 190298aa6..93f99eea3 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -91,11 +91,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let force_prompt_never: bool = force_flag && { if matches.value_source(OPT_FORCE) == Some(ValueSource::CommandLine) { let force_index = matches.index_of(OPT_FORCE).unwrap_or(0); - [OPT_PROMPT, OPT_PROMPT_MORE, OPT_INTERACTIVE] + ![OPT_PROMPT, OPT_PROMPT_MORE, OPT_INTERACTIVE] .iter() - .any(|opt| { - matches.value_source(opt) == Some(ValueSource::CommandLine) - && matches.index_of(opt).unwrap_or(0) < force_index + .any(|flag| { + matches.value_source(flag) == Some(ValueSource::CommandLine) + && matches.index_of(flag).unwrap_or(0) > force_index }) } else { false @@ -110,7 +110,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = Options { force: force_flag, interactive: { - if force_flag && force_prompt_never { + if force_prompt_never { InteractiveMode::Never } else if matches.get_flag(OPT_PROMPT) { InteractiveMode::Always From 2e61580b9966a1fdff7798435b76cdbbe64cac03 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Mon, 17 Oct 2022 17:40:33 -0500 Subject: [PATCH 21/60] Cleaner force_prompt_never --- src/uu/rm/src/rm.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 93f99eea3..b8362adfc 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -89,17 +89,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // If -f(--force) is before any -i (or variants) we want prompts else no prompts let force_prompt_never: bool = force_flag && { - if matches.value_source(OPT_FORCE) == Some(ValueSource::CommandLine) { - let force_index = matches.index_of(OPT_FORCE).unwrap_or(0); - ![OPT_PROMPT, OPT_PROMPT_MORE, OPT_INTERACTIVE] - .iter() - .any(|flag| { - matches.value_source(flag) == Some(ValueSource::CommandLine) - && matches.index_of(flag).unwrap_or(0) > force_index - }) - } else { - false - } + let force_index = matches.index_of(OPT_FORCE).unwrap_or(0); + ![OPT_PROMPT, OPT_PROMPT_MORE, OPT_INTERACTIVE] + .iter() + .any(|flag| { + matches.value_source(flag) == Some(ValueSource::CommandLine) + && matches.index_of(flag).unwrap_or(0) > force_index + }) }; if files.is_empty() && !force_flag { From 50be73d99f498c27652648337e5c83978d8ce259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Wed, 19 Oct 2022 00:13:59 +0300 Subject: [PATCH 22/60] refactor: add automatic conversion for `nix::Errno` --- src/uu/sync/src/sync.rs | 28 +++------------------------- src/uucore/Cargo.toml | 8 ++++---- src/uucore/src/lib/mods/error.rs | 11 +++++++++++ 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 5db957178..eeff191a4 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -11,14 +11,12 @@ extern crate libc; use clap::{crate_version, Arg, ArgAction, Command}; #[cfg(any(target_os = "linux", target_os = "android"))] -use nix::errno::Errno; -#[cfg(any(target_os = "linux", target_os = "android"))] use nix::fcntl::{open, OFlag}; #[cfg(any(target_os = "linux", target_os = "android"))] use nix::sys::stat::Mode; use std::path::Path; use uucore::display::Quotable; -use uucore::error::{UResult, USimpleError}; +use uucore::error::{FromIo, UResult, USimpleError}; use uucore::format_usage; static ABOUT: &str = "Synchronize cached writes to persistent storage"; @@ -183,28 +181,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // Use the Nix open to be able to set the NONBLOCK flags for fifo files #[cfg(any(target_os = "linux", target_os = "android"))] { - match open(Path::new(&f), OFlag::O_NONBLOCK, Mode::empty()) { - Ok(_) => {} - Err(e) => { - if e == Errno::ENOENT { - return Err(USimpleError::new( - 1, - format!("cannot stat {}: No such file or directory", f.quote()), - )); - } - if e == Errno::EACCES { - if Path::new(&f).is_dir() { - return Err(USimpleError::new( - 1, - format!("error opening {}: Permission denied", f.quote()), - )); - } else { - // ignore the issue - // ./target/debug/coreutils sync --data file - } - } - } - } + open(Path::new(&f), OFlag::O_NONBLOCK, Mode::empty()) + .map_err_context(|| format!("cannot stat {}", f.quote()))?; } #[cfg(not(any(target_os = "linux", target_os = "android")))] { diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index af78e3f94..240678b69 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -38,7 +38,7 @@ os_display = "0.1.3" [target.'cfg(unix)'.dependencies] walkdir = { version="2.3.2", optional=true } -nix = { version = "0.25", optional = true, default-features = false, features = ["fs", "uio", "zerocopy"] } +nix = { version = "0.25", default-features = false, features = ["fs", "uio", "zerocopy"] } [dev-dependencies] clap = "4.0" @@ -53,8 +53,8 @@ default = [] # * non-default features encoding = ["data-encoding", "data-encoding-macro", "z85", "thiserror"] entries = ["libc"] -fs = ["libc", "nix", "winapi-util"] -fsext = ["libc", "nix", "time"] +fs = ["libc", "winapi-util"] +fsext = ["libc", "time"] lines = [] memo = ["itertools"] mode = ["libc"] @@ -65,4 +65,4 @@ signals = [] utf8 = [] utmpx = ["time", "time/macros", "libc", "dns-lookup"] wide = [] -pipes = ["nix"] +pipes = [] diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 4cc0b1519..7377c021b 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -508,6 +508,17 @@ impl From for Box { } } +impl FromIo> for Result { + fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { + self.map_err(|e| { + Box::new(UIoError { + context: Some((context)()), + inner: std::io::Error::from_raw_os_error(e as i32), + }) as Box + }) + } +} + /// Shorthand to construct [`UIoError`]-instances. /// /// This macro serves as a convenience call to quickly construct instances of From 5968f53ef434e64772e3f424b2fc6181fe390933 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Thu, 20 Oct 2022 15:42:55 -0500 Subject: [PATCH 23/60] Fixed merge conflict --- src/uu/rm/src/rm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 07c50c2d3..4741d948b 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -550,7 +550,7 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata #[cfg(windows)] fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { use std::os::windows::prelude::MetadataExt; - use winapi::um::winnt::FILE_ATTRIBUTE_READONLY; + use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_READONLY; let not_user_writable = (metadata.file_attributes() & FILE_ATTRIBUTE_READONLY) != 0; if not_user_writable { prompt(&(format!("remove write-protected directory {}? ", path.quote()))) From c6a88c8374d08ecd79e3a91481faeab4dd30a155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Oct 2022 08:19:47 +0000 Subject: [PATCH 24/60] build(deps): bump binary-heap-plus from 0.4.1 to 0.5.0 Bumps [binary-heap-plus](https://github.com/sekineh/binary-heap-plus-rs) from 0.4.1 to 0.5.0. - [Release notes](https://github.com/sekineh/binary-heap-plus-rs/releases) - [Changelog](https://github.com/sekineh/binary-heap-plus-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/sekineh/binary-heap-plus-rs/commits) --- updated-dependencies: - dependency-name: binary-heap-plus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/sort/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc8cf8424..9d4a5a37d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,9 +100,9 @@ dependencies = [ [[package]] name = "binary-heap-plus" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f068638f8ff9e118a9361e66a411eff410e7fb3ecaa23bf9272324f8fc606d7" +checksum = "e4551d8382e911ecc0d0f0ffb602777988669be09447d536ff4388d1def11296" dependencies = [ "compare", ] diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index bcfb7bfa3..2dcf8b2c8 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/sort.rs" [dependencies] -binary-heap-plus = "0.4.1" +binary-heap-plus = "0.5.0" clap = { version = "4.0", features = ["wrap_help", "cargo"] } compare = "0.1.0" ctrlc = { version = "3.0", features = ["termination"] } From 7fd988a7ffb753a0bca1b71cd85e4af9115230df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 22 Oct 2022 08:19:48 +0000 Subject: [PATCH 25/60] build(deps): bump clap_complete from 4.0.2 to 4.0.3 Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.0.2 to 4.0.3. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.0.2...clap_complete-v4.0.3) --- updated-dependencies: - dependency-name: clap_complete dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc8cf8424..979f6b514 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.2" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11cba7abac9b56dfe2f035098cdb3a43946f276e6db83b72c4e692343f9aab9a" +checksum = "dfe581a2035db4174cdbdc91265e1aba50f381577f0510d0ad36c7bc59cc84a3" dependencies = [ "clap 4.0.18", ] From df8ba875167e2a95b801e7929c167f8016ffa9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Sat, 22 Oct 2022 17:20:57 +0300 Subject: [PATCH 26/60] feat: add more implementations for converting `nix::Error` --- src/uucore/src/lib/mods/error.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 7377c021b..67fed9a46 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -519,6 +519,31 @@ impl FromIo> for Result { } } +impl FromIo> for nix::Error { + fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { + Err(Box::new(UIoError { + context: Some((context)()), + inner: std::io::Error::from_raw_os_error(self as i32), + }) as Box) + } +} + +impl From for UIoError { + fn from(f: nix::Error) -> Self { + Self { + context: None, + inner: std::io::Error::from_raw_os_error(f as i32), + } + } +} + +impl From for Box { + fn from(f: nix::Error) -> Self { + let u_error: UIoError = f.into(); + Box::new(u_error) as Self + } +} + /// Shorthand to construct [`UIoError`]-instances. /// /// This macro serves as a convenience call to quickly construct instances of From 990bb4224d3d4f58e14c999b3d7ffae06e8ef304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Sat, 22 Oct 2022 17:45:40 +0300 Subject: [PATCH 27/60] test: add test for `nix::Error` conversions --- src/uucore/src/lib/mods/error.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 67fed9a46..9e1bbc09b 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -729,3 +729,29 @@ impl Display for ClapErrorWrapper { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use nix::errno::Errno; + use std::io::ErrorKind; + + #[test] + fn test_nix_error_conversion() { + for (nix_error, expected_error_kind) in [ + (Errno::EACCES, ErrorKind::PermissionDenied), + (Errno::ENOENT, ErrorKind::NotFound), + (Errno::EEXIST, ErrorKind::AlreadyExists), + ] { + let error = UIoError::from(nix_error); + assert_eq!(expected_error_kind, error.inner.kind()); + } + assert_eq!( + "test: Permission denied", + Err::<(), nix::Error>(Errno::EACCES) + .map_err_context(|| String::from("test")) + .unwrap_err() + .to_string() + ) + } +} From c19c19e4db56678035d4aca4053128dfbcae7ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Sat, 22 Oct 2022 21:26:33 +0300 Subject: [PATCH 28/60] docs: add usage example for `nix::Errno` conversion --- src/uucore/src/lib/mods/error.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 9e1bbc09b..de53f2ef3 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -508,6 +508,20 @@ impl From for Box { } } +/// Enables the conversion from [`Result`] to [`UResult`]. +/// +/// # Examples +/// +/// ``` +/// use uucore::error::FromIo; +/// use nix::errno::Errno; +/// +/// let nix_err = Err::<(), nix::Error>(Errno::EACCES); +/// let uio_result = nix_err.map_err_context(|| String::from("fix me please!")); +/// +/// // prints "fix me please!: Permission denied" +/// println!("{}", uio_result.unwrap_err()); +/// ``` impl FromIo> for Result { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { self.map_err(|e| { From 81ea9521ce0fdb8bc2eb28668c44f944e79da9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Sat, 22 Oct 2022 21:34:45 +0300 Subject: [PATCH 29/60] fix: conditionally enable `nix` error conversions --- src/uu/sync/src/sync.rs | 4 +++- src/uucore/src/lib/mods/error.rs | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index a0139dcdf..08ba6b1d4 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -16,7 +16,9 @@ use nix::fcntl::{open, OFlag}; use nix::sys::stat::Mode; use std::path::Path; use uucore::display::Quotable; -use uucore::error::{FromIo, UResult, USimpleError}; +#[cfg(any(target_os = "linux", target_os = "android"))] +use uucore::error::FromIo; +use uucore::error::{UResult, USimpleError}; use uucore::format_usage; static ABOUT: &str = "Synchronize cached writes to persistent storage"; diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index de53f2ef3..5f6f21b77 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -522,6 +522,7 @@ impl From for Box { /// // prints "fix me please!: Permission denied" /// println!("{}", uio_result.unwrap_err()); /// ``` +#[cfg(any(target_os = "linux", target_os = "android"))] impl FromIo> for Result { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { self.map_err(|e| { @@ -533,6 +534,7 @@ impl FromIo> for Result { } } +#[cfg(any(target_os = "linux", target_os = "android"))] impl FromIo> for nix::Error { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { Err(Box::new(UIoError { @@ -542,6 +544,7 @@ impl FromIo> for nix::Error { } } +#[cfg(any(target_os = "linux", target_os = "android"))] impl From for UIoError { fn from(f: nix::Error) -> Self { Self { @@ -551,6 +554,7 @@ impl From for UIoError { } } +#[cfg(any(target_os = "linux", target_os = "android"))] impl From for Box { fn from(f: nix::Error) -> Self { let u_error: UIoError = f.into(); @@ -746,12 +750,13 @@ impl Display for ClapErrorWrapper { #[cfg(test)] mod tests { - use super::*; - use nix::errno::Errno; - use std::io::ErrorKind; - #[test] + #[cfg(any(target_os = "linux", target_os = "android"))] fn test_nix_error_conversion() { + use super::{FromIo, UIoError}; + use nix::errno::Errno; + use std::io::ErrorKind; + for (nix_error, expected_error_kind) in [ (Errno::EACCES, ErrorKind::PermissionDenied), (Errno::ENOENT, ErrorKind::NotFound), From 744481c8008b70e99f6e2dd4148f7636d51baa8d Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 22 Oct 2022 18:00:17 -0500 Subject: [PATCH 30/60] Updated handle_writable_directory comment --- src/uu/rm/src/rm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 4741d948b..f65ebb2fa 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -530,6 +530,7 @@ fn prompt_file(path: &Path, options: &Options, is_dir: bool) -> bool { } // For directories finding if they are writable or not is a hassle. In Unix we can use the built-in rust crate to to check mode bits. But other os don't have something similar afaik +// Most cases are covered by keep eye out for edge cases #[cfg(unix)] fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { use std::os::unix::fs::PermissionsExt; From 55b3766c10f5867feea0b53a9948f221f422a322 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sun, 23 Oct 2022 00:18:56 -0400 Subject: [PATCH 31/60] clippy fixes --- src/uu/chcon/src/chcon.rs | 10 ++--- src/uu/chgrp/src/chgrp.rs | 2 +- src/uu/chown/src/chown.rs | 6 +-- src/uu/cp/src/copydir.rs | 2 +- src/uu/cp/src/cp.rs | 8 ++-- src/uu/dd/src/parseargs/unit_tests.rs | 4 +- src/uu/df/src/df.rs | 18 ++++----- src/uu/echo/src/echo.rs | 3 ++ src/uu/head/src/head.rs | 8 ++-- src/uu/hostname/src/hostname.rs | 8 ++-- src/uu/id/src/id.rs | 6 +-- src/uu/ls/src/ls.rs | 56 +++++++++++++-------------- src/uu/realpath/src/realpath.rs | 2 +- src/uu/sort/src/sort.rs | 6 +-- src/uu/tail/src/args.rs | 10 ++--- src/uu/test/src/test.rs | 10 ++--- src/uu/touch/src/touch.rs | 2 +- src/uu/uniq/src/uniq.rs | 2 +- src/uu/who/src/who.rs | 4 +- tests/by-util/test_chown.rs | 4 +- tests/by-util/test_ls.rs | 10 ++--- tests/common/random.rs | 6 +-- 22 files changed, 95 insertions(+), 92 deletions(-) diff --git a/src/uu/chcon/src/chcon.rs b/src/uu/chcon/src/chcon.rs index 1742ca1a2..2abf8d40a 100644 --- a/src/uu/chcon/src/chcon.rs +++ b/src/uu/chcon/src/chcon.rs @@ -100,7 +100,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } CommandLineMode::ContextBased { context } => { - let c_context = match os_str_to_c_string(&context) { + let c_context = match os_str_to_c_string(context) { Ok(context) => context, Err(_r) => { @@ -198,7 +198,7 @@ pub fn uu_app() -> Command { .long(options::REFERENCE) .value_name("RFILE") .value_hint(clap::ValueHint::FilePath) - .conflicts_with_all(&[options::USER, options::ROLE, options::TYPE, options::RANGE]) + .conflicts_with_all([options::USER, options::ROLE, options::TYPE, options::RANGE]) .help( "Use security context of RFILE, rather than specifying \ a CONTEXT value.", @@ -249,7 +249,7 @@ pub fn uu_app() -> Command { Arg::new(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) .short('H') .requires(options::RECURSIVE) - .overrides_with_all(&[ + .overrides_with_all([ options::sym_links::FOLLOW_DIR_SYM_LINKS, options::sym_links::NO_FOLLOW_SYM_LINKS, ]) @@ -263,7 +263,7 @@ pub fn uu_app() -> Command { Arg::new(options::sym_links::FOLLOW_DIR_SYM_LINKS) .short('L') .requires(options::RECURSIVE) - .overrides_with_all(&[ + .overrides_with_all([ options::sym_links::FOLLOW_ARG_DIR_SYM_LINK, options::sym_links::NO_FOLLOW_SYM_LINKS, ]) @@ -277,7 +277,7 @@ pub fn uu_app() -> Command { Arg::new(options::sym_links::NO_FOLLOW_SYM_LINKS) .short('P') .requires(options::RECURSIVE) - .overrides_with_all(&[ + .overrides_with_all([ options::sym_links::FOLLOW_ARG_DIR_SYM_LINK, options::sym_links::FOLLOW_DIR_SYM_LINKS, ]) diff --git a/src/uu/chgrp/src/chgrp.rs b/src/uu/chgrp/src/chgrp.rs index a97f6f1ef..3b8d0bab0 100644 --- a/src/uu/chgrp/src/chgrp.rs +++ b/src/uu/chgrp/src/chgrp.rs @@ -146,7 +146,7 @@ pub fn uu_app() -> Command { Arg::new(options::traverse::NO_TRAVERSE) .short(options::traverse::NO_TRAVERSE.chars().next().unwrap()) .help("do not traverse any symbolic links (default)") - .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]) + .overrides_with_all([options::traverse::TRAVERSE, options::traverse::EVERY]) .action(ArgAction::SetTrue), ) .arg( diff --git a/src/uu/chown/src/chown.rs b/src/uu/chown/src/chown.rs index d99516d92..c64290cd2 100644 --- a/src/uu/chown/src/chown.rs +++ b/src/uu/chown/src/chown.rs @@ -156,21 +156,21 @@ pub fn uu_app() -> Command { Arg::new(options::traverse::TRAVERSE) .short(options::traverse::TRAVERSE.chars().next().unwrap()) .help("if a command line argument is a symbolic link to a directory, traverse it") - .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]) + .overrides_with_all([options::traverse::EVERY, options::traverse::NO_TRAVERSE]) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::EVERY) .short(options::traverse::EVERY.chars().next().unwrap()) .help("traverse every symbolic link to a directory encountered") - .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]) + .overrides_with_all([options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::traverse::NO_TRAVERSE) .short(options::traverse::NO_TRAVERSE.chars().next().unwrap()) .help("do not traverse any symbolic links (default)") - .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]) + .overrides_with_all([options::traverse::TRAVERSE, options::traverse::EVERY]) .action(ArgAction::SetTrue), ) .arg( diff --git a/src/uu/cp/src/copydir.rs b/src/uu/cp/src/copydir.rs index 8930282fb..3527e4827 100644 --- a/src/uu/cp/src/copydir.rs +++ b/src/uu/cp/src/copydir.rs @@ -66,7 +66,7 @@ fn get_local_to_root_parent( adjust_canonicalization(path), adjust_canonicalization(parent), ); - let path = path.strip_prefix(&parent)?; + let path = path.strip_prefix(parent)?; Ok(path.to_path_buf()) } None => Ok(path.to_path_buf()), diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 3a1697039..b7ea1129d 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -427,7 +427,7 @@ pub fn uu_app() -> Command { )) .num_args(0..) .value_name("ATTR_LIST") - .overrides_with_all(&[ + .overrides_with_all([ options::ARCHIVE, options::PRESERVE_DEFAULT_ATTRIBUTES, options::NO_PRESERVE, @@ -443,7 +443,7 @@ pub fn uu_app() -> Command { Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES) .short('p') .long(options::PRESERVE_DEFAULT_ATTRIBUTES) - .overrides_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE]) + .overrides_with_all([options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE]) .help("same as --preserve=mode,ownership(unix only),timestamps") .action(ArgAction::SetTrue), ) @@ -451,7 +451,7 @@ pub fn uu_app() -> Command { Arg::new(options::NO_PRESERVE) .long(options::NO_PRESERVE) .value_name("ATTR_LIST") - .overrides_with_all(&[ + .overrides_with_all([ options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::ARCHIVE, @@ -492,7 +492,7 @@ pub fn uu_app() -> Command { Arg::new(options::ARCHIVE) .short('a') .long(options::ARCHIVE) - .overrides_with_all(&[ + .overrides_with_all([ options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::NO_PRESERVE, diff --git a/src/uu/dd/src/parseargs/unit_tests.rs b/src/uu/dd/src/parseargs/unit_tests.rs index 18eeb33a2..7084f8114 100644 --- a/src/uu/dd/src/parseargs/unit_tests.rs +++ b/src/uu/dd/src/parseargs/unit_tests.rs @@ -86,7 +86,7 @@ fn unimplemented_flags_should_error() { fn test_status_level_absent() { let args = &["if=foo.file", "of=bar.file"]; - assert_eq!(Parser::new().parse(args).unwrap().status, None) + assert_eq!(Parser::new().parse(args).unwrap().status, None); } #[test] @@ -96,7 +96,7 @@ fn test_status_level_none() { assert_eq!( Parser::new().parse(args).unwrap().status, Some(StatusLevel::None) - ) + ); } #[test] diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 8d26bc6f8..8cefd642f 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -509,7 +509,7 @@ pub fn uu_app() -> Command { .short('B') .long("block-size") .value_name("SIZE") - .overrides_with_all(&[OPT_KILO, OPT_BLOCKSIZE]) + .overrides_with_all([OPT_KILO, OPT_BLOCKSIZE]) .help( "scale sizes by SIZE before printing them; e.g.\ '-BM' prints sizes in units of 1,048,576 bytes", @@ -526,7 +526,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_HUMAN_READABLE_BINARY) .short('h') .long("human-readable") - .overrides_with_all(&[OPT_HUMAN_READABLE_DECIMAL, OPT_HUMAN_READABLE_BINARY]) + .overrides_with_all([OPT_HUMAN_READABLE_DECIMAL, OPT_HUMAN_READABLE_BINARY]) .help("print sizes in human readable format (e.g., 1K 234M 2G)") .action(ArgAction::SetTrue), ) @@ -534,7 +534,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_HUMAN_READABLE_DECIMAL) .short('H') .long("si") - .overrides_with_all(&[OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL]) + .overrides_with_all([OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL]) .help("likewise, but use powers of 1000 not 1024") .action(ArgAction::SetTrue), ) @@ -550,7 +550,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_KILO) .short('k') .help("like --block-size=1K") - .overrides_with_all(&[OPT_BLOCKSIZE, OPT_KILO]) + .overrides_with_all([OPT_BLOCKSIZE, OPT_KILO]) .action(ArgAction::SetTrue), ) .arg( @@ -564,7 +564,7 @@ pub fn uu_app() -> Command { .arg( Arg::new(OPT_NO_SYNC) .long("no-sync") - .overrides_with_all(&[OPT_SYNC, OPT_NO_SYNC]) + .overrides_with_all([OPT_SYNC, OPT_NO_SYNC]) .help("do not invoke sync before getting usage info (default)") .action(ArgAction::SetTrue), ) @@ -577,9 +577,9 @@ pub fn uu_app() -> Command { .require_equals(true) .use_value_delimiter(true) .value_parser(OUTPUT_FIELD_LIST) - .default_missing_values(&OUTPUT_FIELD_LIST) - .default_values(&["source", "size", "used", "avail", "pcent", "target"]) - .conflicts_with_all(&[OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE]) + .default_missing_values(OUTPUT_FIELD_LIST) + .default_values(["source", "size", "used", "avail", "pcent", "target"]) + .conflicts_with_all([OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE]) .help( "use the output format defined by FIELD_LIST, \ or print all fields if FIELD_LIST is omitted.", @@ -596,7 +596,7 @@ pub fn uu_app() -> Command { .arg( Arg::new(OPT_SYNC) .long("sync") - .overrides_with_all(&[OPT_NO_SYNC, OPT_SYNC]) + .overrides_with_all([OPT_NO_SYNC, OPT_SYNC]) .help("invoke sync before getting usage info (non-windows only)") .action(ArgAction::SetTrue), ) diff --git a/src/uu/echo/src/echo.rs b/src/uu/echo/src/echo.rs index ebf0d46e7..65819a800 100644 --- a/src/uu/echo/src/echo.rs +++ b/src/uu/echo/src/echo.rs @@ -64,6 +64,9 @@ fn print_escaped(input: &str, mut output: impl Write) -> io::Result { let mut buffer = ['\\'; 2]; + // TODO `cargo +nightly clippy` complains that `.peek()` is never + // called on `iter`. However, `peek()` is called inside the + // `parse_code()` function that borrows `iter`. let mut iter = input.chars().peekable(); while let Some(mut c) = iter.next() { let mut start = 1; diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index a01fe94f7..32a4ad376 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -59,7 +59,7 @@ pub fn uu_app() -> Command { NUM bytes of each file\ ", ) - .overrides_with_all(&[options::BYTES_NAME, options::LINES_NAME]) + .overrides_with_all([options::BYTES_NAME, options::LINES_NAME]) .allow_hyphen_values(true), ) .arg( @@ -74,7 +74,7 @@ pub fn uu_app() -> Command { NUM lines of each file\ ", ) - .overrides_with_all(&[options::LINES_NAME, options::BYTES_NAME]) + .overrides_with_all([options::LINES_NAME, options::BYTES_NAME]) .allow_hyphen_values(true), ) .arg( @@ -83,7 +83,7 @@ pub fn uu_app() -> Command { .long("quiet") .visible_alias("silent") .help("never print headers giving file names") - .overrides_with_all(&[options::VERBOSE_NAME, options::QUIET_NAME]) + .overrides_with_all([options::VERBOSE_NAME, options::QUIET_NAME]) .action(ArgAction::SetTrue), ) .arg( @@ -91,7 +91,7 @@ pub fn uu_app() -> Command { .short('v') .long("verbose") .help("always print headers giving file names") - .overrides_with_all(&[options::QUIET_NAME, options::VERBOSE_NAME]) + .overrides_with_all([options::QUIET_NAME, options::VERBOSE_NAME]) .action(ArgAction::SetTrue), ) .arg( diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index b9699d99a..92950f137 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -81,7 +81,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_DOMAIN) .short('d') .long("domain") - .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) + .overrides_with_all([OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) .help("Display the name of the DNS domain if possible") .action(ArgAction::SetTrue), ) @@ -89,7 +89,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_IP_ADDRESS) .short('i') .long("ip-address") - .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) + .overrides_with_all([OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) .help("Display the network address(es) of the host") .action(ArgAction::SetTrue), ) @@ -97,7 +97,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_FQDN) .short('f') .long("fqdn") - .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) + .overrides_with_all([OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) .help("Display the FQDN (Fully Qualified Domain Name) (default)") .action(ArgAction::SetTrue), ) @@ -105,7 +105,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_SHORT) .short('s') .long("short") - .overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) + .overrides_with_all([OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT]) .help("Display the short hostname (the portion before the first dot) if possible") .action(ArgAction::SetTrue), ) diff --git a/src/uu/id/src/id.rs b/src/uu/id/src/id.rs index 720339545..61a975978 100644 --- a/src/uu/id/src/id.rs +++ b/src/uu/id/src/id.rs @@ -348,7 +348,7 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::OPT_AUDIT) .short('A') - .conflicts_with_all(&[ + .conflicts_with_all([ options::OPT_GROUP, options::OPT_EFFECTIVE_USER, options::OPT_HUMAN_READABLE, @@ -382,7 +382,7 @@ pub fn uu_app() -> Command { Arg::new(options::OPT_GROUPS) .short('G') .long(options::OPT_GROUPS) - .conflicts_with_all(&[ + .conflicts_with_all([ options::OPT_GROUP, options::OPT_EFFECTIVE_USER, options::OPT_CONTEXT, @@ -443,7 +443,7 @@ pub fn uu_app() -> Command { Arg::new(options::OPT_CONTEXT) .short('Z') .long(options::OPT_CONTEXT) - .conflicts_with_all(&[options::OPT_GROUP, options::OPT_EFFECTIVE_USER]) + .conflicts_with_all([options::OPT_GROUP, options::OPT_EFFECTIVE_USER]) .help(CONTEXT_HELP_TEXT) .action(ArgAction::SetTrue), ) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index a30cda01d..054ff9127 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -981,7 +981,7 @@ pub fn uu_app() -> Command { ]) .hide_possible_values(true) .require_equals(true) - .overrides_with_all(&[ + .overrides_with_all([ options::FORMAT, options::format::COLUMNS, options::format::LONG, @@ -993,7 +993,7 @@ pub fn uu_app() -> Command { Arg::new(options::format::COLUMNS) .short('C') .help("Display the files in columns.") - .overrides_with_all(&[ + .overrides_with_all([ options::FORMAT, options::format::COLUMNS, options::format::LONG, @@ -1007,7 +1007,7 @@ pub fn uu_app() -> Command { .short('l') .long(options::format::LONG) .help("Display detailed information.") - .overrides_with_all(&[ + .overrides_with_all([ options::FORMAT, options::format::COLUMNS, options::format::LONG, @@ -1020,7 +1020,7 @@ pub fn uu_app() -> Command { Arg::new(options::format::ACROSS) .short('x') .help("List entries in rows instead of in columns.") - .overrides_with_all(&[ + .overrides_with_all([ options::FORMAT, options::format::COLUMNS, options::format::LONG, @@ -1042,7 +1042,7 @@ pub fn uu_app() -> Command { Arg::new(options::format::COMMAS) .short('m') .help("List entries separated by commas.") - .overrides_with_all(&[ + .overrides_with_all([ options::FORMAT, options::format::COLUMNS, options::format::LONG, @@ -1114,7 +1114,7 @@ pub fn uu_app() -> Command { "c", "escape", ]) - .overrides_with_all(&[ + .overrides_with_all([ options::QUOTING_STYLE, options::quoting::LITERAL, options::quoting::ESCAPE, @@ -1126,7 +1126,7 @@ pub fn uu_app() -> Command { .short('N') .long(options::quoting::LITERAL) .help("Use literal quoting style. Equivalent to `--quoting-style=literal`") - .overrides_with_all(&[ + .overrides_with_all([ options::QUOTING_STYLE, options::quoting::LITERAL, options::quoting::ESCAPE, @@ -1139,7 +1139,7 @@ pub fn uu_app() -> Command { .short('b') .long(options::quoting::ESCAPE) .help("Use escape quoting style. Equivalent to `--quoting-style=escape`") - .overrides_with_all(&[ + .overrides_with_all([ options::QUOTING_STYLE, options::quoting::LITERAL, options::quoting::ESCAPE, @@ -1152,7 +1152,7 @@ pub fn uu_app() -> Command { .short('Q') .long(options::quoting::C) .help("Use C quoting style. Equivalent to `--quoting-style=c`") - .overrides_with_all(&[ + .overrides_with_all([ options::QUOTING_STYLE, options::quoting::LITERAL, options::quoting::ESCAPE, @@ -1166,14 +1166,14 @@ pub fn uu_app() -> Command { .short('q') .long(options::HIDE_CONTROL_CHARS) .help("Replace control characters with '?' if they are not escaped.") - .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]) + .overrides_with_all([options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SHOW_CONTROL_CHARS) .long(options::SHOW_CONTROL_CHARS) .help("Show control characters 'as is' if they are not escaped.") - .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]) + .overrides_with_all([options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]) .action(ArgAction::SetTrue), ) // Time arguments @@ -1192,7 +1192,7 @@ pub fn uu_app() -> Command { ]) .hide_possible_values(true) .require_equals(true) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), + .overrides_with_all([options::TIME, options::time::ACCESS, options::time::CHANGE]), ) .arg( Arg::new(options::time::CHANGE) @@ -1203,7 +1203,7 @@ pub fn uu_app() -> Command { time. When explicitly sorting by time (--sort=time or -t) or when not \ using a long listing format, sort according to the status change time.", ) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]) + .overrides_with_all([options::TIME, options::time::ACCESS, options::time::CHANGE]) .action(ArgAction::SetTrue), ) .arg( @@ -1215,7 +1215,7 @@ pub fn uu_app() -> Command { sorting by time (--sort=time or -t) or when not using a long listing \ format, sort according to the access time.", ) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]) + .overrides_with_all([options::TIME, options::time::ACCESS, options::time::CHANGE]) .action(ArgAction::SetTrue), ) // Hide and ignore @@ -1251,7 +1251,7 @@ pub fn uu_app() -> Command { .value_name("field") .value_parser(["name", "none", "time", "size", "version", "extension"]) .require_equals(true) - .overrides_with_all(&[ + .overrides_with_all([ options::SORT, options::sort::SIZE, options::sort::TIME, @@ -1264,7 +1264,7 @@ pub fn uu_app() -> Command { Arg::new(options::sort::SIZE) .short('S') .help("Sort by file size, largest first.") - .overrides_with_all(&[ + .overrides_with_all([ options::SORT, options::sort::SIZE, options::sort::TIME, @@ -1278,7 +1278,7 @@ pub fn uu_app() -> Command { Arg::new(options::sort::TIME) .short('t') .help("Sort by modification time (the 'mtime' in the inode), newest first.") - .overrides_with_all(&[ + .overrides_with_all([ options::SORT, options::sort::SIZE, options::sort::TIME, @@ -1292,7 +1292,7 @@ pub fn uu_app() -> Command { Arg::new(options::sort::VERSION) .short('v') .help("Natural sort of (version) numbers in the filenames.") - .overrides_with_all(&[ + .overrides_with_all([ options::SORT, options::sort::SIZE, options::sort::TIME, @@ -1306,7 +1306,7 @@ pub fn uu_app() -> Command { Arg::new(options::sort::EXTENSION) .short('X') .help("Sort alphabetically by entry extension.") - .overrides_with_all(&[ + .overrides_with_all([ options::SORT, options::sort::SIZE, options::sort::TIME, @@ -1324,7 +1324,7 @@ pub fn uu_app() -> Command { directory. This is especially useful when listing very large directories, \ since not doing any sorting can be noticeably faster.", ) - .overrides_with_all(&[ + .overrides_with_all([ options::SORT, options::sort::SIZE, options::sort::TIME, @@ -1343,7 +1343,7 @@ pub fn uu_app() -> Command { "When showing file information for a symbolic link, show information for the \ file the link references rather than the link itself.", ) - .overrides_with_all(&[ + .overrides_with_all([ options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, @@ -1357,7 +1357,7 @@ pub fn uu_app() -> Command { "Do not dereference symlinks except when they link to directories and are \ given as command line arguments.", ) - .overrides_with_all(&[ + .overrides_with_all([ options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, @@ -1369,7 +1369,7 @@ pub fn uu_app() -> Command { .short('H') .long(options::dereference::ARGS) .help("Do not dereference symlinks except when given as command line arguments.") - .overrides_with_all(&[ + .overrides_with_all([ options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, @@ -1509,7 +1509,7 @@ pub fn uu_app() -> Command { none (default), slash (-p), file-type (--file-type), classify (-F)", ) .value_parser(["none", "slash", "file-type", "classify"]) - .overrides_with_all(&[ + .overrides_with_all([ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, options::indicator_style::CLASSIFY, @@ -1545,7 +1545,7 @@ pub fn uu_app() -> Command { .default_missing_value("always") .require_equals(true) .num_args(0..=1) - .overrides_with_all(&[ + .overrides_with_all([ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, options::indicator_style::CLASSIFY, @@ -1556,7 +1556,7 @@ pub fn uu_app() -> Command { Arg::new(options::indicator_style::FILE_TYPE) .long(options::indicator_style::FILE_TYPE) .help("Same as --classify, but do not append '*'") - .overrides_with_all(&[ + .overrides_with_all([ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, options::indicator_style::CLASSIFY, @@ -1568,7 +1568,7 @@ pub fn uu_app() -> Command { Arg::new(options::indicator_style::SLASH) .short('p') .help("Append / indicator to directories.") - .overrides_with_all(&[ + .overrides_with_all([ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, options::indicator_style::CLASSIFY, @@ -1584,7 +1584,7 @@ pub fn uu_app() -> Command { .value_name("TIME_STYLE") .env("TIME_STYLE") .value_parser(NonEmptyStringValueParser::new()) - .overrides_with_all(&[options::TIME_STYLE]), + .overrides_with_all([options::TIME_STYLE]), ) .arg( Arg::new(options::FULL_TIME) diff --git a/src/uu/realpath/src/realpath.rs b/src/uu/realpath/src/realpath.rs index b5f9ebd11..5ca5d687b 100644 --- a/src/uu/realpath/src/realpath.rs +++ b/src/uu/realpath/src/realpath.rs @@ -130,7 +130,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_PHYSICAL) .short('P') .long(OPT_PHYSICAL) - .overrides_with_all(&[OPT_STRIP, OPT_LOGICAL]) + .overrides_with_all([OPT_STRIP, OPT_LOGICAL]) .help("resolve symlinks as encountered (default)") .action(ArgAction::SetTrue), ) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index c1bb750be..9d23034ad 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -1336,7 +1336,7 @@ pub fn uu_app() -> Command { "version", "random", ]) - .conflicts_with_all(&options::modes::ALL_SORT_MODES), + .conflicts_with_all(options::modes::ALL_SORT_MODES), ) .arg(make_sort_mode_arg( options::modes::HUMAN_NUMERIC, @@ -1373,7 +1373,7 @@ pub fn uu_app() -> Command { .short('d') .long(options::DICTIONARY_ORDER) .help("consider only blanks and alphanumeric characters") - .conflicts_with_all(&[ + .conflicts_with_all([ options::modes::NUMERIC, options::modes::GENERAL_NUMERIC, options::modes::HUMAN_NUMERIC, @@ -1425,7 +1425,7 @@ pub fn uu_app() -> Command { .short('i') .long(options::IGNORE_NONPRINTING) .help("ignore nonprinting characters") - .conflicts_with_all(&[ + .conflicts_with_all([ options::modes::NUMERIC, options::modes::GENERAL_NUMERIC, options::modes::HUMAN_NUMERIC, diff --git a/src/uu/tail/src/args.rs b/src/uu/tail/src/args.rs index 4c3f0c56d..6bc9baf0b 100644 --- a/src/uu/tail/src/args.rs +++ b/src/uu/tail/src/args.rs @@ -334,7 +334,7 @@ pub fn uu_app() -> Command { .short('c') .long(options::BYTES) .allow_hyphen_values(true) - .overrides_with_all(&[options::BYTES, options::LINES]) + .overrides_with_all([options::BYTES, options::LINES]) .help("Number of bytes to print"), ) .arg( @@ -352,7 +352,7 @@ pub fn uu_app() -> Command { .short('n') .long(options::LINES) .allow_hyphen_values(true) - .overrides_with_all(&[options::BYTES, options::LINES]) + .overrides_with_all([options::BYTES, options::LINES]) .help("Number of lines to print"), ) .arg( @@ -366,7 +366,7 @@ pub fn uu_app() -> Command { .short('q') .long(options::verbosity::QUIET) .visible_alias("silent") - .overrides_with_all(&[options::verbosity::QUIET, options::verbosity::VERBOSE]) + .overrides_with_all([options::verbosity::QUIET, options::verbosity::VERBOSE]) .help("Never output headers giving file names") .action(ArgAction::SetTrue), ) @@ -392,7 +392,7 @@ pub fn uu_app() -> Command { Arg::new(options::verbosity::VERBOSE) .short('v') .long(options::verbosity::VERBOSE) - .overrides_with_all(&[options::verbosity::QUIET, options::verbosity::VERBOSE]) + .overrides_with_all([options::verbosity::QUIET, options::verbosity::VERBOSE]) .help("Always output headers giving file names") .action(ArgAction::SetTrue), ) @@ -421,7 +421,7 @@ pub fn uu_app() -> Command { Arg::new(options::FOLLOW_RETRY) .short('F') .help("Same as --follow=name --retry") - .overrides_with_all(&[options::RETRY, options::FOLLOW]) + .overrides_with_all([options::RETRY, options::FOLLOW]) .action(ArgAction::SetTrue), ) .arg( diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index aaeb351e5..bc274bc8b 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -452,18 +452,18 @@ mod tests { fn test_integer_op() { let a = OsStr::new("18446744073709551616"); let b = OsStr::new("0"); - assert_eq!(integers(a, b, OsStr::new("-lt")).unwrap(), false); + assert!(!integers(a, b, OsStr::new("-lt")).unwrap()); let a = OsStr::new("18446744073709551616"); let b = OsStr::new("0"); - assert_eq!(integers(a, b, OsStr::new("-gt")).unwrap(), true); + assert!(integers(a, b, OsStr::new("-gt")).unwrap()); let a = OsStr::new("-1"); let b = OsStr::new("0"); - assert_eq!(integers(a, b, OsStr::new("-lt")).unwrap(), true); + assert!(integers(a, b, OsStr::new("-lt")).unwrap()); let a = OsStr::new("42"); let b = OsStr::new("42"); - assert_eq!(integers(a, b, OsStr::new("-eq")).unwrap(), true); + assert!(integers(a, b, OsStr::new("-eq")).unwrap()); let a = OsStr::new("42"); let b = OsStr::new("42"); - assert_eq!(integers(a, b, OsStr::new("-ne")).unwrap(), false); + assert!(!integers(a, b, OsStr::new("-ne")).unwrap()); } } diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index f397d2eaf..39f328d87 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -254,7 +254,7 @@ pub fn uu_app() -> Command { .value_parser(ValueParser::os_string()) .value_hint(clap::ValueHint::AnyPath), ) - .group(ArgGroup::new(options::SOURCES).args(&[ + .group(ArgGroup::new(options::SOURCES).args([ options::sources::CURRENT, options::sources::DATE, options::sources::REFERENCE, diff --git a/src/uu/uniq/src/uniq.rs b/src/uu/uniq/src/uniq.rs index 45f5c05f2..a66393acb 100644 --- a/src/uu/uniq/src/uniq.rs +++ b/src/uu/uniq/src/uniq.rs @@ -336,7 +336,7 @@ pub fn uu_app() -> Command { .num_args(0..=1) .default_missing_value("separate") .require_equals(true) - .conflicts_with_all(&[ + .conflicts_with_all([ options::REPEATED, options::ALL_REPEATED, options::UNIQUE, diff --git a/src/uu/who/src/who.rs b/src/uu/who/src/who.rs index 4729d68ac..d41ce1e79 100644 --- a/src/uu/who/src/who.rs +++ b/src/uu/who/src/who.rs @@ -250,7 +250,7 @@ pub fn uu_app() -> Command { .long(options::MESG) .short('T') .visible_short_alias('w') - .visible_aliases(&["message", "writable"]) + .visible_aliases(["message", "writable"]) .help("add user's message status as +, - or ?") .action(ArgAction::SetTrue), ) @@ -350,7 +350,7 @@ impl Who { println!("{}", users.join(" ")); println!("# users={}", users.len()); } else { - let records = Utmpx::iter_all_records_from(f).peekable(); + let records = Utmpx::iter_all_records_from(f); if self.include_heading { self.print_heading(); diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index b54412857..a4634b0de 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -708,7 +708,7 @@ fn test_chown_file_notexisting() { .fails(); // TODO: uncomment once "failed to change ownership of '{}' to {}" added to stdout - // result.stderr_contains(&"retained as"); + // result.stderr_contains("retained as"); // TODO: uncomment once message changed from "cannot dereference" to "cannot access" - // result.stderr_contains(&"cannot access 'not_existing': No such file or directory"); + // result.stderr_contains("cannot access 'not_existing': No such file or directory"); } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 310c84290..0b3b3f788 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1863,7 +1863,7 @@ fn test_ls_recursive() { #[cfg(not(windows))] result.stdout_contains("a/b:\nb"); #[cfg(windows)] - result.stdout_contains(&"a\\b:\nb"); + result.stdout_contains("a\\b:\nb"); } #[test] @@ -2093,13 +2093,13 @@ fn test_ls_indicator_style() { .ucmd() .arg(format!("--indicator-style={}", opt)) .succeeds() - .stdout_contains(&"/"); + .stdout_contains("/"); } // Same test as above, but with the alternate flags. let options = vec!["--classify", "--file-type", "-p"]; for opt in options { - scene.ucmd().arg(opt).succeeds().stdout_contains(&"/"); + scene.ucmd().arg(opt).succeeds().stdout_contains("/"); } // Classify and File-Type all contain indicators for pipes and links. @@ -2110,7 +2110,7 @@ fn test_ls_indicator_style() { .ucmd() .arg(format!("--indicator-style={}", opt)) .succeeds() - .stdout_contains(&"@"); + .stdout_contains("@"); } } @@ -3195,7 +3195,7 @@ fn test_ls_context_format() { ] { let format = format!("--format={}", word); ts.ucmd() - .args(&[&"-Z", &format.as_str(), &"/"]) + .args(&["-Z", format.as_str(), "/"]) .succeeds() .stdout_only( unwrap_or_return!(expected_result(&ts, &["-Z", format.as_str(), "/"])).stdout_str(), diff --git a/tests/common/random.rs b/tests/common/random.rs index 0e422572f..29f3d2775 100644 --- a/tests/common/random.rs +++ b/tests/common/random.rs @@ -58,11 +58,11 @@ impl Distribution for AlphanumericNewline { /// use rand::distributions::Alphanumeric; /// /// // generates a 100 byte string with characters from AlphanumericNewline -/// let random_string = RandomString::generate(&AlphanumericNewline, 100); +/// let random_string = RandomString::generate(AlphanumericNewline, 100); /// assert_eq!(100, random_string.len()); /// /// // generates a 100 byte string with 10 newline characters not ending with a newline -/// let string = RandomString::generate_with_delimiter(&Alphanumeric, b'\n', 10, false, 100); +/// let string = RandomString::generate_with_delimiter(Alphanumeric, b'\n', 10, false, 100); /// assert_eq!(100, random_string.len()); /// ``` pub struct RandomString; @@ -108,7 +108,7 @@ impl RandomString { /// use crate::common::random::{AlphanumericNewline, RandomString}; /// /// // generates a 100 byte string with 10 '\0' byte characters not ending with a '\0' byte - /// let string = RandomString::generate_with_delimiter(&AlphanumericNewline, 0, 10, false, 100); + /// let string = RandomString::generate_with_delimiter(AlphanumericNewline, 0, 10, false, 100); /// assert_eq!(100, random_string.len()); /// assert_eq!( /// 10, From d48a65096682fe8259c4709bfbf9efae8cb30db3 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sun, 23 Oct 2022 17:40:30 -0400 Subject: [PATCH 32/60] cp: restrict copy through dangling symlink with -f Change `cp` to terminate with an error when attempting to copy through a dangling symbolic link with the `--force` option. Before this commit, touch src ln -s no-such-file dest cp -f src dest would incorrectly replace `dest` with the contents of `src`. After this commit, it correctly fails with the error message cp: not writing through dangling symlink 'dest' --- src/uu/cp/src/cp.rs | 16 +++++++++++----- tests/by-util/test_cp.rs | 13 +++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 3a1697039..b81a31e54 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1264,10 +1264,6 @@ fn copy_file( symlinked_files: &mut HashSet, source_in_command_line: bool, ) -> CopyResult<()> { - if file_or_link_exists(dest) { - handle_existing_dest(source, dest, options, source_in_command_line)?; - } - // Fail if dest is a dangling symlink or a symlink this program created previously if dest.is_symlink() { if FileInformation::from_path(dest, false) @@ -1281,7 +1277,13 @@ fn copy_file( ))); } let copy_contents = options.dereference(source_in_command_line) || !source.is_symlink(); - if copy_contents && !dest.exists() { + if copy_contents + && !dest.exists() + && !matches!( + options.overwrite, + OverwriteMode::Clobber(ClobberMode::RemoveDestination) + ) + { return Err(Error::Error(format!( "not writing through dangling symlink '{}'", dest.display() @@ -1289,6 +1291,10 @@ fn copy_file( } } + if file_or_link_exists(dest) { + handle_existing_dest(source, dest, options, source_in_command_line)?; + } + if options.verbose { println!("{}", context_for(source, dest)); } diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 8285905c5..cb0f38484 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1827,6 +1827,19 @@ fn test_copy_through_dangling_symlink_no_dereference_2() { .stderr_only("cp: not writing through dangling symlink 'target'"); } +/// Test that copy through a dangling symbolic link fails, even with --force. +#[test] +#[cfg(not(windows))] +fn test_copy_through_dangling_symlink_force() { + let (at, mut ucmd) = at_and_ucmd!(); + at.touch("src"); + at.symlink_file("no-such-file", "dest"); + ucmd.args(&["--force", "src", "dest"]) + .fails() + .stderr_only("cp: not writing through dangling symlink 'dest'"); + assert!(!at.file_exists("dest")); +} + #[test] #[cfg(unix)] fn test_cp_archive_on_nonexistent_file() { From 6e8f8034ba362e80bdd43cbf355a4c6e0b1dcc6e Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 24 Oct 2022 20:01:15 +0200 Subject: [PATCH 33/60] {cp, mv} -i --update source existing should not do anything and exit 0 Should fix tests/mv/update.sh --- src/uu/cp/src/cp.rs | 6 ++++++ src/uu/mv/src/mv.rs | 6 ++++++ tests/by-util/test_cp.rs | 12 ++++++++++++ tests/by-util/test_mv.rs | 19 +++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 3a1697039..b3ef4f56a 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1264,6 +1264,12 @@ fn copy_file( symlinked_files: &mut HashSet, source_in_command_line: bool, ) -> CopyResult<()> { + if options.update && options.overwrite == OverwriteMode::Interactive(ClobberMode::Standard) { + // `cp -i --update old new` when `new` exists doesn't copy anything + // and exit with 0 + return Ok(()); + } + if file_or_link_exists(dest) { handle_existing_dest(source, dest, options, source_in_command_line)?; } diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index ded46539f..4697fac4a 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -371,6 +371,12 @@ fn rename(from: &Path, to: &Path, b: &Behavior) -> io::Result<()> { let mut backup_path = None; if to.exists() { + if b.update && b.overwrite == OverwriteMode::Interactive { + // `mv -i --update old new` when `new` exists doesn't move anything + // and exit with 0 + return Ok(()); + } + match b.overwrite { OverwriteMode::NoClobber => return Ok(()), OverwriteMode::Interactive => { diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 8285905c5..5a97db0bd 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -215,6 +215,18 @@ fn test_cp_target_directory_is_file() { .stderr_contains(format!("'{}' is not a directory", TEST_HOW_ARE_YOU_SOURCE)); } +#[test] +fn test_cp_arg_update_interactive() { + new_ucmd!() + .arg(TEST_HELLO_WORLD_SOURCE) + .arg(TEST_HOW_ARE_YOU_SOURCE) + .arg("-i") + .arg("--update") + .succeeds() + .no_stdout() + .no_stderr(); +} + #[test] fn test_cp_arg_interactive() { let (at, mut ucmd) = at_and_ucmd!(); diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 200053ba6..9dd06c9f1 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -184,6 +184,25 @@ fn test_mv_interactive() { assert!(at.file_exists(file_b)); } +#[test] +fn test_mv_arg_update_interactive() { + let (at, mut ucmd) = at_and_ucmd!(); + + let file_a = "test_mv_replace_file_a"; + let file_b = "test_mv_replace_file_b"; + + at.touch(file_a); + at.touch(file_b); + + ucmd.arg(file_a) + .arg(file_b) + .arg("-i") + .arg("--update") + .succeeds() + .no_stdout() + .no_stderr(); +} + #[test] fn test_mv_no_clobber() { let (at, mut ucmd) = at_and_ucmd!(); From 9f1ac221cd245d2b1db8d60bdc26fe9658cea169 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 25 Oct 2022 00:29:49 +0200 Subject: [PATCH 34/60] chown: fails when XXXX. or XXXX: is provided (when XXXX is numeric values) If the arg starts with an id numeric value, the group isn't set but the separator is provided, we should fail with an error Should fix tests/chown/separator.sh --- src/uu/chown/src/chown.rs | 13 +++++++++++++ tests/by-util/test_chown.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/uu/chown/src/chown.rs b/src/uu/chown/src/chown.rs index d99516d92..f434faaa7 100644 --- a/src/uu/chown/src/chown.rs +++ b/src/uu/chown/src/chown.rs @@ -246,6 +246,19 @@ fn parse_spec(spec: &str, sep: char) -> UResult<(Option, Option)> { } else { None }; + + if user.chars().next().map(char::is_numeric).unwrap_or(false) + && group.is_empty() + && spec != user + { + // if the arg starts with an id numeric value, the group isn't set but the separator is provided, + // we should fail with an error + return Err(USimpleError::new( + 1, + format!("invalid spec: {}", spec.quote()), + )); + } + Ok((uid, gid)) } diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index b54412857..c786afa8e 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -423,6 +423,38 @@ fn test_chown_only_user_id() { .stderr_contains("failed to change"); } +#[test] +fn test_chown_fail_id() { + // test chown 1111. file.txt + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let result = scene.cmd_keepenv("id").arg("-u").run(); + if skipping_test_is_okay(&result, "id: cannot find name for group ID") { + return; + } + let user_id = String::from(result.stdout_str().trim()); + assert!(!user_id.is_empty()); + + let file1 = "test_chown_file1"; + at.touch(file1); + + scene + .ucmd() + .arg(format!("{}:", user_id)) + .arg(file1) + .fails() + .stderr_contains("invalid spec"); + + scene + .ucmd() + .arg(format!("{}.", user_id)) + .arg(file1) + .fails() + .stderr_contains("invalid spec"); +} + /// Test for setting the owner to a user ID for a user that does not exist. /// /// For example: From 58caf625d15d90763ae32d37b5d83febfc1ba2db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 06:51:50 +0000 Subject: [PATCH 35/60] build(deps): bump time from 0.3.15 to 0.3.16 Bumps [time](https://github.com/time-rs/time) from 0.3.15 to 0.3.16. - [Release notes](https://github.com/time-rs/time/releases) - [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md) - [Commits](https://github.com/time-rs/time/compare/v0.3.15...v0.3.16) --- updated-dependencies: - dependency-name: time dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a12ec25c9..d1d61e12b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2076,21 +2076,32 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" dependencies = [ "itoa", "libc", "num_threads", + "serde", + "time-core", "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +dependencies = [ + "time-core", +] [[package]] name = "typenum" From 2213ad5d1ce8a609c27634b99435e9b45474f9a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 06:51:19 +0000 Subject: [PATCH 36/60] build(deps): bump libc from 0.2.135 to 0.2.136 Bumps [libc](https://github.com/rust-lang/libc) from 0.2.135 to 0.2.136. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.135...0.2.136) --- updated-dependencies: - dependency-name: libc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/chmod/Cargo.toml | 2 +- src/uu/cp/Cargo.toml | 2 +- src/uu/hostid/Cargo.toml | 2 +- src/uu/logname/Cargo.toml | 2 +- src/uu/mkfifo/Cargo.toml | 2 +- src/uu/mknod/Cargo.toml | 2 +- src/uu/nice/Cargo.toml | 2 +- src/uu/nohup/Cargo.toml | 2 +- src/uu/nproc/Cargo.toml | 2 +- src/uu/pathchk/Cargo.toml | 2 +- src/uu/rmdir/Cargo.toml | 2 +- src/uu/sync/Cargo.toml | 2 +- src/uu/tail/Cargo.toml | 2 +- src/uu/tee/Cargo.toml | 2 +- src/uu/test/Cargo.toml | 2 +- src/uu/timeout/Cargo.toml | 2 +- src/uu/whoami/Cargo.toml | 2 +- src/uu/yes/Cargo.toml | 2 +- src/uucore/Cargo.toml | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a12ec25c9..5438defb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1145,9 +1145,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "55edcf6c0bb319052dea84732cf99db461780fd5e8d3eb46ab6ff312ab31f197" [[package]] name = "libloading" diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index c794ad821..deacbc0f2 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -16,7 +16,7 @@ path = "src/chmod.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "mode"] } [[bin]] diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index 15ce7c8f5..a54fdc212 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -21,7 +21,7 @@ path = "src/cp.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } filetime = "0.2" -libc = "0.2.135" +libc = "0.2.136" quick-error = "2.0.1" selinux = { version="0.3", optional=true } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms", "mode"] } diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 0938a1bec..6a81dd897 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -16,7 +16,7 @@ path = "src/hostid.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index e688346ce..ba300fbf1 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/logname.rs" [dependencies] -libc = "0.2.135" +libc = "0.2.136" clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/mkfifo/Cargo.toml b/src/uu/mkfifo/Cargo.toml index f932697ff..e24204f94 100644 --- a/src/uu/mkfifo/Cargo.toml +++ b/src/uu/mkfifo/Cargo.toml @@ -16,7 +16,7 @@ path = "src/mkfifo.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index 7e21983ff..96ca9ab48 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -17,7 +17,7 @@ path = "src/mknod.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "^0.2.135" +libc = "^0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["mode"] } [[bin]] diff --git a/src/uu/nice/Cargo.toml b/src/uu/nice/Cargo.toml index c062d4db3..0e435e4c3 100644 --- a/src/uu/nice/Cargo.toml +++ b/src/uu/nice/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nice.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" nix = { version = "0.25", default-features = false } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/nohup/Cargo.toml b/src/uu/nohup/Cargo.toml index 5603d96c0..9b13c7ec5 100644 --- a/src/uu/nohup/Cargo.toml +++ b/src/uu/nohup/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nohup.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" atty = "0.2" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index e830b06a2..e351ab3c8 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/nproc.rs" [dependencies] -libc = "0.2.135" +libc = "0.2.136" num_cpus = "1.10" clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/pathchk/Cargo.toml b/src/uu/pathchk/Cargo.toml index b25450b89..5475eaa8a 100644 --- a/src/uu/pathchk/Cargo.toml +++ b/src/uu/pathchk/Cargo.toml @@ -16,7 +16,7 @@ path = "src/pathchk.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/rmdir/Cargo.toml b/src/uu/rmdir/Cargo.toml index a96a2cec1..b66ee12eb 100644 --- a/src/uu/rmdir/Cargo.toml +++ b/src/uu/rmdir/Cargo.toml @@ -17,7 +17,7 @@ path = "src/rmdir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } -libc = "0.2.135" +libc = "0.2.136" [[bin]] name = "rmdir" diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index dc5754e43..ea6652522 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -16,7 +16,7 @@ path = "src/sync.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["wide"] } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index a912bf352..7abb18b3c 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -17,7 +17,7 @@ path = "src/tail.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" memchr = "2.5.0" notify = { version = "=5.0.0", features=["macos_kqueue"]} uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index 311e09875..1b3a44e67 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -16,7 +16,7 @@ path = "src/tee.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" retain_mut = "=0.1.7" # ToDO: [2021-01-01; rivy; maint/MinSRV] ~ v0.1.5 uses const generics which aren't stabilized until rust v1.51.0 uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc"] } diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index 28b7362b1..7e0fae115 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -16,7 +16,7 @@ path = "src/test.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [target.'cfg(target_os = "redox")'.dependencies] diff --git a/src/uu/timeout/Cargo.toml b/src/uu/timeout/Cargo.toml index 77adcfe57..48c632de0 100644 --- a/src/uu/timeout/Cargo.toml +++ b/src/uu/timeout/Cargo.toml @@ -16,7 +16,7 @@ path = "src/timeout.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" nix = { version = "0.25", default-features = false, features = ["signal"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["process", "signals"] } diff --git a/src/uu/whoami/Cargo.toml b/src/uu/whoami/Cargo.toml index f3a277e89..34402278f 100644 --- a/src/uu/whoami/Cargo.toml +++ b/src/uu/whoami/Cargo.toml @@ -22,7 +22,7 @@ uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=[ windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_NetworkManagement_NetManagement", "Win32_System_WindowsProgramming", "Win32_Foundation"] } [target.'cfg(unix)'.dependencies] -libc = "0.2.135" +libc = "0.2.136" [[bin]] name = "whoami" diff --git a/src/uu/yes/Cargo.toml b/src/uu/yes/Cargo.toml index 677d60a5f..47cd10f53 100644 --- a/src/uu/yes/Cargo.toml +++ b/src/uu/yes/Cargo.toml @@ -16,7 +16,7 @@ path = "src/yes.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.135" +libc = "0.2.136" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["pipes"] } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index d9489c281..a83090857 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -32,7 +32,7 @@ time = { version="0.3", optional=true, features = ["formatting", "local-offset", data-encoding = { version="2.1", optional=true } data-encoding-macro = { version="0.1.12", optional=true } z85 = { version="3.0.5", optional=true } -libc = { version="0.2.135", optional=true } +libc = { version="0.2.136", optional=true } once_cell = "1.13.1" os_display = "0.1.3" From 52d82d54a3736a6298e2f0cb4b9ed186020f6a83 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 25 Oct 2022 23:44:05 +0200 Subject: [PATCH 37/60] Revert "hashsum: test b3sum::test_nonames for real (#4027)" This reverts commit 02f6fa7b249f44d4fa5b10c5f008fadaaa9d6f56. --- src/uu/hashsum/src/hashsum.rs | 9 +++++---- tests/by-util/test_hashsum.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 2d01c9d64..828436595 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -276,10 +276,11 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { }; let check = matches.get_flag("check"); let tag = matches.get_flag("tag"); - let nonames = *matches - .try_get_one("no-names") - .unwrap_or(Some(&false)) - .unwrap(); + let nonames = if binary_name == "b3sum" { + matches.get_flag("no-names") + } else { + false + }; let status = matches.get_flag("status"); let quiet = matches.get_flag("quiet") || status; let strict = matches.get_flag("strict"); diff --git a/tests/by-util/test_hashsum.rs b/tests/by-util/test_hashsum.rs index e8f716815..f30eb42ce 100644 --- a/tests/by-util/test_hashsum.rs +++ b/tests/by-util/test_hashsum.rs @@ -34,7 +34,7 @@ macro_rules! test_digest { fn test_nonames() { let ts = TestScenario::new("hashsum"); // EXPECTED_FILE has no newline character at the end - if DIGEST_ARG == "--b3sum" { + if DIGEST_ARG == "b3sum" { // Option only available on b3sum assert_eq!(format!("{0}\n{0}\n", ts.fixtures.read(EXPECTED_FILE)), ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("--no-names").arg("input.txt").arg("-").pipe_in_fixture("input.txt") From 69c1f28c6646edfa4063d274b3ac510c4869acca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Oct 2022 06:42:06 +0000 Subject: [PATCH 38/60] build(deps): bump libc from 0.2.136 to 0.2.137 Bumps [libc](https://github.com/rust-lang/libc) from 0.2.136 to 0.2.137. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.136...0.2.137) --- updated-dependencies: - dependency-name: libc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/chmod/Cargo.toml | 2 +- src/uu/cp/Cargo.toml | 2 +- src/uu/hostid/Cargo.toml | 2 +- src/uu/logname/Cargo.toml | 2 +- src/uu/mkfifo/Cargo.toml | 2 +- src/uu/mknod/Cargo.toml | 2 +- src/uu/nice/Cargo.toml | 2 +- src/uu/nohup/Cargo.toml | 2 +- src/uu/nproc/Cargo.toml | 2 +- src/uu/pathchk/Cargo.toml | 2 +- src/uu/rmdir/Cargo.toml | 2 +- src/uu/sync/Cargo.toml | 2 +- src/uu/tail/Cargo.toml | 2 +- src/uu/tee/Cargo.toml | 2 +- src/uu/test/Cargo.toml | 2 +- src/uu/timeout/Cargo.toml | 2 +- src/uu/whoami/Cargo.toml | 2 +- src/uu/yes/Cargo.toml | 2 +- src/uucore/Cargo.toml | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5438defb1..2ba1c90bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1145,9 +1145,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.136" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55edcf6c0bb319052dea84732cf99db461780fd5e8d3eb46ab6ff312ab31f197" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libloading" diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index deacbc0f2..adb72a256 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -16,7 +16,7 @@ path = "src/chmod.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "mode"] } [[bin]] diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index a54fdc212..b54e68464 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -21,7 +21,7 @@ path = "src/cp.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } filetime = "0.2" -libc = "0.2.136" +libc = "0.2.137" quick-error = "2.0.1" selinux = { version="0.3", optional=true } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms", "mode"] } diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 6a81dd897..81dfb68d1 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -16,7 +16,7 @@ path = "src/hostid.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index ba300fbf1..72c264fe6 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/logname.rs" [dependencies] -libc = "0.2.136" +libc = "0.2.137" clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/mkfifo/Cargo.toml b/src/uu/mkfifo/Cargo.toml index e24204f94..c0c319cff 100644 --- a/src/uu/mkfifo/Cargo.toml +++ b/src/uu/mkfifo/Cargo.toml @@ -16,7 +16,7 @@ path = "src/mkfifo.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index 96ca9ab48..03a09279f 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -17,7 +17,7 @@ path = "src/mknod.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "^0.2.136" +libc = "^0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["mode"] } [[bin]] diff --git a/src/uu/nice/Cargo.toml b/src/uu/nice/Cargo.toml index 0e435e4c3..f9ea3c38c 100644 --- a/src/uu/nice/Cargo.toml +++ b/src/uu/nice/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nice.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" nix = { version = "0.25", default-features = false } uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } diff --git a/src/uu/nohup/Cargo.toml b/src/uu/nohup/Cargo.toml index 9b13c7ec5..883c90b9d 100644 --- a/src/uu/nohup/Cargo.toml +++ b/src/uu/nohup/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nohup.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" atty = "0.2" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index e351ab3c8..057062a73 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/nproc.rs" [dependencies] -libc = "0.2.136" +libc = "0.2.137" num_cpus = "1.10" clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/pathchk/Cargo.toml b/src/uu/pathchk/Cargo.toml index 5475eaa8a..9c77eff09 100644 --- a/src/uu/pathchk/Cargo.toml +++ b/src/uu/pathchk/Cargo.toml @@ -16,7 +16,7 @@ path = "src/pathchk.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/rmdir/Cargo.toml b/src/uu/rmdir/Cargo.toml index b66ee12eb..5616742a5 100644 --- a/src/uu/rmdir/Cargo.toml +++ b/src/uu/rmdir/Cargo.toml @@ -17,7 +17,7 @@ path = "src/rmdir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } -libc = "0.2.136" +libc = "0.2.137" [[bin]] name = "rmdir" diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index ea6652522..3558868a5 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -16,7 +16,7 @@ path = "src/sync.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["wide"] } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index 7abb18b3c..4c2552d0c 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -17,7 +17,7 @@ path = "src/tail.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" memchr = "2.5.0" notify = { version = "=5.0.0", features=["macos_kqueue"]} uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index 1b3a44e67..b9c6a36a9 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -16,7 +16,7 @@ path = "src/tee.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" retain_mut = "=0.1.7" # ToDO: [2021-01-01; rivy; maint/MinSRV] ~ v0.1.5 uses const generics which aren't stabilized until rust v1.51.0 uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc"] } diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index 7e0fae115..f1ae083e0 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -16,7 +16,7 @@ path = "src/test.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [target.'cfg(target_os = "redox")'.dependencies] diff --git a/src/uu/timeout/Cargo.toml b/src/uu/timeout/Cargo.toml index 48c632de0..6c42553a9 100644 --- a/src/uu/timeout/Cargo.toml +++ b/src/uu/timeout/Cargo.toml @@ -16,7 +16,7 @@ path = "src/timeout.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" nix = { version = "0.25", default-features = false, features = ["signal"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["process", "signals"] } diff --git a/src/uu/whoami/Cargo.toml b/src/uu/whoami/Cargo.toml index 34402278f..4c1b5c2ab 100644 --- a/src/uu/whoami/Cargo.toml +++ b/src/uu/whoami/Cargo.toml @@ -22,7 +22,7 @@ uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=[ windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_NetworkManagement_NetManagement", "Win32_System_WindowsProgramming", "Win32_Foundation"] } [target.'cfg(unix)'.dependencies] -libc = "0.2.136" +libc = "0.2.137" [[bin]] name = "whoami" diff --git a/src/uu/yes/Cargo.toml b/src/uu/yes/Cargo.toml index 47cd10f53..1f2db513b 100644 --- a/src/uu/yes/Cargo.toml +++ b/src/uu/yes/Cargo.toml @@ -16,7 +16,7 @@ path = "src/yes.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -libc = "0.2.136" +libc = "0.2.137" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["pipes"] } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index a83090857..e5f78ef95 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -32,7 +32,7 @@ time = { version="0.3", optional=true, features = ["formatting", "local-offset", data-encoding = { version="2.1", optional=true } data-encoding-macro = { version="0.1.12", optional=true } z85 = { version="3.0.5", optional=true } -libc = { version="0.2.136", optional=true } +libc = { version="0.2.137", optional=true } once_cell = "1.13.1" os_display = "0.1.3" From bbc349589658a2630e3cfa073bdd3276cdda3109 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 26 Oct 2022 11:10:26 +0200 Subject: [PATCH 39/60] hashsum: enable testing --no-names Co-authored-by: Huijeong Kim --- src/uu/hashsum/src/hashsum.rs | 9 ++++----- tests/by-util/test_hashsum.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 828436595..87c79fe1f 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -276,11 +276,10 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { }; let check = matches.get_flag("check"); let tag = matches.get_flag("tag"); - let nonames = if binary_name == "b3sum" { - matches.get_flag("no-names") - } else { - false - }; + let nonames = *matches + .try_get_one("no-names") + .unwrap_or(None) + .unwrap_or(&false); let status = matches.get_flag("status"); let quiet = matches.get_flag("quiet") || status; let strict = matches.get_flag("strict"); diff --git a/tests/by-util/test_hashsum.rs b/tests/by-util/test_hashsum.rs index f30eb42ce..e8f716815 100644 --- a/tests/by-util/test_hashsum.rs +++ b/tests/by-util/test_hashsum.rs @@ -34,7 +34,7 @@ macro_rules! test_digest { fn test_nonames() { let ts = TestScenario::new("hashsum"); // EXPECTED_FILE has no newline character at the end - if DIGEST_ARG == "b3sum" { + if DIGEST_ARG == "--b3sum" { // Option only available on b3sum assert_eq!(format!("{0}\n{0}\n", ts.fixtures.read(EXPECTED_FILE)), ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("--no-names").arg("input.txt").arg("-").pipe_in_fixture("input.txt") From 34eabca299b8938bc61760091120bcca9e1a1519 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 25 Oct 2022 22:29:46 +0200 Subject: [PATCH 40/60] pwd: support the env variable 'POSIXLY_CORRECT' Should fix tests/misc/pwd-option.sh --- src/uu/pwd/src/pwd.rs | 5 ++++- tests/by-util/test_pwd.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/uu/pwd/src/pwd.rs b/src/uu/pwd/src/pwd.rs index 732df19f6..b1e2b30ff 100644 --- a/src/uu/pwd/src/pwd.rs +++ b/src/uu/pwd/src/pwd.rs @@ -126,7 +126,10 @@ fn logical_path() -> io::Result { #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - let cwd = if matches.get_flag(OPT_LOGICAL) { + // if POSIXLY_CORRECT is set, we want to a logical resolution. + // This produces a different output when doing mkdir -p a/b && ln -s a/b c && cd c && pwd + // We should get c in this case instead of a/b at the end of the path + let cwd = if matches.get_flag(OPT_LOGICAL) || env::var("POSIXLY_CORRECT").is_ok() { logical_path() } else { physical_path() diff --git a/tests/by-util/test_pwd.rs b/tests/by-util/test_pwd.rs index 0ae63c895..0ae0cc909 100644 --- a/tests/by-util/test_pwd.rs +++ b/tests/by-util/test_pwd.rs @@ -90,6 +90,35 @@ fn test_symlinked_default() { env.ucmd.succeeds().stdout_is(env.subdir + "\n"); } +#[test] +fn test_symlinked_default_posix() { + let mut env = symlinked_env(); + env.ucmd + .env("POSIXLY_CORRECT", "1") + .succeeds() + .stdout_is(env.symdir.clone() + "\n"); +} + +#[test] +fn test_symlinked_default_posix_l() { + let mut env = symlinked_env(); + env.ucmd + .env("POSIXLY_CORRECT", "1") + .arg("-L") + .succeeds() + .stdout_is(env.symdir + "\n"); +} + +#[test] +fn test_symlinked_default_posix_p() { + let mut env = symlinked_env(); + env.ucmd + .env("POSIXLY_CORRECT", "1") + .arg("-P") + .succeeds() + .stdout_is(env.symdir + "\n"); +} + #[cfg(not(windows))] pub mod untrustworthy_pwd_var { use std::path::Path; From 2eb0b6dfe09c61a84814ea5aa391bad5c752dc80 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 27 Oct 2022 15:33:20 +0200 Subject: [PATCH 41/60] numfmt: round values if precision is 0 --- src/uu/numfmt/src/format.rs | 3 +-- tests/by-util/test_numfmt.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/uu/numfmt/src/format.rs b/src/uu/numfmt/src/format.rs index 5e61ce794..b97993f21 100644 --- a/src/uu/numfmt/src/format.rs +++ b/src/uu/numfmt/src/format.rs @@ -272,14 +272,13 @@ fn transform_to( let (i2, s) = consider_suffix(s, &opts.to, round_method, precision)?; let i2 = i2 / (opts.to_unit as f64); Ok(match s { - None if precision > 0 => { + None => { format!( "{:.precision$}", round_with_precision(i2, round_method, precision), precision = precision ) } - None => format!("{}", i2), Some(s) if precision > 0 => { format!( "{:.precision$}{}", diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 72a9e39a9..821b8e70b 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -530,7 +530,7 @@ fn test_round() { new_ucmd!() .args(&[ "--to=si", - &format!("--round={}", method), + &format!("--round={method}"), "--", "9001", "-9001", @@ -542,6 +542,32 @@ fn test_round() { } } +#[test] +fn test_round_with_to_unit() { + for (method, exp) in [ + ("from-zero", ["6", "-6", "5.9", "-5.9", "5.86", "-5.86"]), + ("towards-zero", ["5", "-5", "5.8", "-5.8", "5.85", "-5.85"]), + ("up", ["6", "-5", "5.9", "-5.8", "5.86", "-5.85"]), + ("down", ["5", "-6", "5.8", "-5.9", "5.85", "-5.86"]), + ("nearest", ["6", "-6", "5.9", "-5.9", "5.86", "-5.86"]), + ] { + new_ucmd!() + .args(&[ + "--to-unit=1024", + &format!("--round={method}"), + "--", + "6000", + "-6000", + "6000.0", + "-6000.0", + "6000.00", + "-6000.00", + ]) + .succeeds() + .stdout_only(exp.join("\n") + "\n"); + } +} + #[test] fn test_suffix_is_added_if_not_supplied() { new_ucmd!() From c7af9a6a80adfd458edea7ce1eadcdec57f97b14 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Thu, 27 Oct 2022 13:41:55 -0500 Subject: [PATCH 42/60] Bump libc version from "0.2.135" to "0.2.136" --- src/uu/rm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/rm/Cargo.toml b/src/uu/rm/Cargo.toml index 1467f7568..75bde3d3e 100644 --- a/src/uu/rm/Cargo.toml +++ b/src/uu/rm/Cargo.toml @@ -21,7 +21,7 @@ remove_dir_all = "0.7.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } [target.'cfg(unix)'.dependencies] -libc = "0.2.135" +libc = "0.2.136" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Storage_FileSystem"] } From 3a8feedf2d2cf66495ca580bf70e0c3c0be7da7b Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sat, 29 Oct 2022 16:50:41 +0200 Subject: [PATCH 43/60] numfmt: allow hyphen values for --field option --- src/uu/numfmt/src/numfmt.rs | 1 + tests/by-util/test_numfmt.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index ba76b7f77..f6a1f2739 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -275,6 +275,7 @@ pub fn uu_app() -> Command { .long(options::FIELD) .help("replace the numbers in these input fields; see FIELDS below") .value_name("FIELDS") + .allow_hyphen_values(true) .default_value(options::FIELD_DEFAULT), ) .arg( diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 821b8e70b..49de861fb 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -375,6 +375,14 @@ fn test_format_selected_fields() { .stdout_only("1000 2K 3000 4000 5K 6K\n"); } +#[test] +fn test_format_implied_range_and_field() { + new_ucmd!() + .args(&["--from=auto", "--field", "-2,4", "1K 2K 3K 4K 5K 6K"]) + .succeeds() + .stdout_only("1000 2000 3K 4000 5K 6K\n"); +} + #[test] fn test_should_succeed_if_selected_field_out_of_range() { new_ucmd!() From 4b4222ffe357e452d23d43a0359d007465f6ea60 Mon Sep 17 00:00:00 2001 From: Pat Laster Date: Sat, 29 Oct 2022 11:09:52 -0500 Subject: [PATCH 44/60] Bump libc version from "0.2.136" to "0.2.137" --- src/uu/rm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/rm/Cargo.toml b/src/uu/rm/Cargo.toml index 75bde3d3e..3cd49b11b 100644 --- a/src/uu/rm/Cargo.toml +++ b/src/uu/rm/Cargo.toml @@ -21,7 +21,7 @@ remove_dir_all = "0.7.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } [target.'cfg(unix)'.dependencies] -libc = "0.2.136" +libc = "0.2.137" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Storage_FileSystem"] } From d5ab502f42ddc494067fc17e79657a8e0bf65e2d Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Oct 2022 23:52:55 +0200 Subject: [PATCH 45/60] build: harden GnuComment.yml permissions Signed-off-by: Alex --- .github/workflows/GnuComment.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/GnuComment.yml b/.github/workflows/GnuComment.yml index d1e34807c..bb64232a9 100644 --- a/.github/workflows/GnuComment.yml +++ b/.github/workflows/GnuComment.yml @@ -6,8 +6,13 @@ on: types: - completed +permissions: {} jobs: post-comment: + permissions: + actions: read # to list workflow runs artifacts + pull-requests: write # to comment on pr + runs-on: ubuntu-latest if: > github.event.workflow_run.event == 'pull_request' From 5d27c19853e3dbc4579b4d89d81e970b4f1d5e33 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 31 Oct 2022 09:26:28 +0100 Subject: [PATCH 46/60] numfmt: add test for "--field -" (all fields) --- tests/by-util/test_numfmt.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 49de861fb..bcae09aa3 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -399,6 +399,14 @@ fn test_format_selected_field_range() { .stdout_only("1K 2000 3000 4000 5000 6K\n"); } +#[test] +fn test_format_all_fields() { + new_ucmd!() + .args(&["--from=auto", "--field", "-", "1K 2K 3K 4K 5K 6K"]) + .succeeds() + .stdout_only("1000 2000 3000 4000 5000 6000\n"); +} + #[test] fn test_should_succeed_if_range_out_of_bounds() { new_ucmd!() From 27c233f294bb38b2dc0321f5e83c016c94288283 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 31 Oct 2022 14:53:41 +0100 Subject: [PATCH 47/60] numfmt: allow "-" in field list --- src/uu/numfmt/src/numfmt.rs | 11 +++++++---- tests/by-util/test_numfmt.rs | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index f6a1f2739..d490d3fee 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -158,12 +158,15 @@ fn parse_options(args: &ArgMatches) -> Result { Ok(0) }?; - let fields = match args.get_one::(options::FIELD).unwrap().as_str() { - "-" => vec![Range { + let fields = args.get_one::(options::FIELD).unwrap().as_str(); + // a lone "-" means "all fields", even as part of a list of fields + let fields = if fields.split(',').any(|x| x == "-") { + vec![Range { low: 1, high: std::usize::MAX, - }], - v => Range::from_list(v)?, + }] + } else { + Range::from_list(fields)? }; let format = match args.get_one::(options::FORMAT) { diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index bcae09aa3..f4fa94298 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -401,10 +401,14 @@ fn test_format_selected_field_range() { #[test] fn test_format_all_fields() { - new_ucmd!() - .args(&["--from=auto", "--field", "-", "1K 2K 3K 4K 5K 6K"]) - .succeeds() - .stdout_only("1000 2000 3000 4000 5000 6000\n"); + let all_fields_patterns = vec!["-", "-,3", "3,-", "1,-,3"]; + + for pattern in all_fields_patterns { + new_ucmd!() + .args(&["--from=auto", "--field", pattern, "1K 2K 3K 4K 5K 6K"]) + .succeeds() + .stdout_only("1000 2000 3000 4000 5000 6000\n"); + } } #[test] From 2d4810b91b8741db9cf902a8fb9428d17a5ecfa6 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 1 Nov 2022 10:04:46 +0100 Subject: [PATCH 48/60] numfmt: allow ' ' as field separator --- src/uu/numfmt/src/numfmt.rs | 2 +- src/uucore/src/lib/mods/ranges.rs | 2 +- tests/by-util/test_numfmt.rs | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index d490d3fee..1e826e68e 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -160,7 +160,7 @@ fn parse_options(args: &ArgMatches) -> Result { let fields = args.get_one::(options::FIELD).unwrap().as_str(); // a lone "-" means "all fields", even as part of a list of fields - let fields = if fields.split(',').any(|x| x == "-") { + let fields = if fields.split(&[',', ' ']).any(|x| x == "-") { vec![Range { low: 1, high: std::usize::MAX, diff --git a/src/uucore/src/lib/mods/ranges.rs b/src/uucore/src/lib/mods/ranges.rs index aba4c9ca2..76a61b9a6 100644 --- a/src/uucore/src/lib/mods/ranges.rs +++ b/src/uucore/src/lib/mods/ranges.rs @@ -75,7 +75,7 @@ impl Range { pub fn from_list(list: &str) -> Result, String> { let mut ranges = Vec::new(); - for item in list.split(',') { + for item in list.split(&[',', ' ']) { let range_item = FromStr::from_str(item) .map_err(|e| format!("range {} was invalid: {}", item.quote(), e))?; ranges.push(range_item); diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index f4fa94298..108c26fd0 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -373,6 +373,11 @@ fn test_format_selected_fields() { .args(&["--from=auto", "--field", "1,4,3", "1K 2K 3K 4K 5K 6K"]) .succeeds() .stdout_only("1000 2K 3000 4000 5K 6K\n"); + + new_ucmd!() + .args(&["--from=auto", "--field", "1,4 3", "1K 2K 3K 4K 5K 6K"]) + .succeeds() + .stdout_only("1000 2K 3000 4000 5K 6K\n"); } #[test] @@ -401,7 +406,7 @@ fn test_format_selected_field_range() { #[test] fn test_format_all_fields() { - let all_fields_patterns = vec!["-", "-,3", "3,-", "1,-,3"]; + let all_fields_patterns = vec!["-", "-,3", "3,-", "1,-,3", "- 3"]; for pattern in all_fields_patterns { new_ucmd!() From 4fdfedf61eaba399b8cd093e730f3daa328226ba Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 2 Nov 2022 10:20:04 +0100 Subject: [PATCH 49/60] build-gnu: fix test for numfmt --- util/build-gnu.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index a9df0f401..4ef9b4744 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -218,6 +218,9 @@ sed -i -e "s/ginstall: creating directory/install: creating directory/g" tests/i # disable this test case sed -i -Ez "s/\n([^\n#]*pad-3\.2[^\n]*)\n([^\n]*)\n([^\n]*)/\n# uutils\/numfmt supports padding = LONG_MIN\n#\1\n#\2\n#\3/" tests/misc/numfmt.pl +# Update the GNU error message to match the one generated by clap +sed -i -e "s/\$prog: multiple field specifications/error: The argument '--field ' was provided more than once, but cannot be used multiple times\n\nUsage: numfmt [OPTION]... [NUMBER]...\n\n\nFor more information try '--help'/g" tests/misc/numfmt.pl + # GNU doesn't support width > INT_MAX # disable these test cases sed -i -E "s|^([^#]*2_31.*)$|#\1|g" tests/misc/printf-cov.pl From 7b88276462970a246b6931a854b5637089dc7420 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Nov 2022 06:05:35 +0000 Subject: [PATCH 50/60] build(deps): bump vmactions/freebsd-vm from 0.2.9 to 0.3.0 Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 0.2.9 to 0.3.0. - [Release notes](https://github.com/vmactions/freebsd-vm/releases) - [Commits](https://github.com/vmactions/freebsd-vm/compare/v0.2.9...v0.3.0) --- updated-dependencies: - dependency-name: vmactions/freebsd-vm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/CICD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index d09cd40f2..1fb086fc8 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -897,7 +897,7 @@ jobs: - uses: Swatinem/rust-cache@v1 - name: Prepare, build and test ## spell-checker:ignore (ToDO) sshfs usesh vmactions - uses: vmactions/freebsd-vm@v0.2.9 + uses: vmactions/freebsd-vm@v0.3.0 with: usesh: true # sync: sshfs From cce8d766fed0baf9238c00cef9182a48f66a37c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 06:30:15 +0000 Subject: [PATCH 51/60] build(deps): bump byte-unit from 4.0.14 to 4.0.17 Bumps [byte-unit](https://github.com/magiclen/byte-unit) from 4.0.14 to 4.0.17. - [Release notes](https://github.com/magiclen/byte-unit/releases) - [Commits](https://github.com/magiclen/byte-unit/compare/v4.0.14...v4.0.17) --- updated-dependencies: - dependency-name: byte-unit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 08669a761..7c0e2d18d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,10 +190,11 @@ checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" [[package]] name = "byte-unit" -version = "4.0.14" +version = "4.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ebf10dda65f19ff0f42ea15572a359ed60d7fc74fdc984d90310937be0014b" +checksum = "581ad4b3d627b0c09a0ccb2912148f839acaca0b93cf54cbe42b6c674e86079c" dependencies = [ + "serde", "utf8-width", ] From 53c4b0b81e528adc340dd803bf597fa3fad1bb4c Mon Sep 17 00:00:00 2001 From: David Matos Date: Sun, 30 Oct 2022 19:57:39 +0100 Subject: [PATCH 52/60] mktemp: allow default missing value --- src/uu/mktemp/src/mktemp.rs | 3 +++ tests/by-util/test_mktemp.rs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 5e7234b76..a00664d95 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -440,6 +440,9 @@ pub fn uu_app() -> Command { may contain slashes, but mktemp creates only the final component", ) .value_name("DIR") + // Allows use of default argument just by setting --tmpdir. Else, + // use provided input to generate tmpdir + .num_args(0..=1) .value_hint(clap::ValueHint::DirPath), ) .arg( diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index 57448474f..d19f5d6d1 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -825,3 +825,9 @@ fn test_nonexistent_dir_prefix() { ); } } + +#[test] +fn test_default_missing_value() { + let scene = TestScenario::new(util_name!()); + scene.ucmd().arg("-d").arg("--tmpdir").succeeds(); +} From c2a6f6c77b3dacac9047865e87e91666917f4d08 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 3 Nov 2022 21:14:38 +0100 Subject: [PATCH 53/60] Remove unused dependencies --- Cargo.lock | 3 --- src/uu/dir/Cargo.toml | 1 - src/uu/dircolors/Cargo.toml | 1 - src/uu/vdir/Cargo.toml | 1 - 4 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd09545da..a29b073f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2358,7 +2358,6 @@ name = "uu_dir" version = "0.0.16" dependencies = [ "clap 4.0.18", - "selinux", "uu_ls", "uucore", ] @@ -2368,7 +2367,6 @@ name = "uu_dircolors" version = "0.0.16" dependencies = [ "clap 4.0.18", - "glob", "uucore", ] @@ -3136,7 +3134,6 @@ name = "uu_vdir" version = "0.0.16" dependencies = [ "clap 4.0.18", - "selinux", "uu_ls", "uucore", ] diff --git a/src/uu/dir/Cargo.toml b/src/uu/dir/Cargo.toml index 37d16cee8..4ddb9cdd9 100644 --- a/src/uu/dir/Cargo.toml +++ b/src/uu/dir/Cargo.toml @@ -17,7 +17,6 @@ path = "src/dir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } -selinux = { version = "0.3", optional = true } uu_ls = { version = ">=0.0.16", path="../ls"} [[bin]] diff --git a/src/uu/dircolors/Cargo.toml b/src/uu/dircolors/Cargo.toml index 0c2294a57..578fbbd38 100644 --- a/src/uu/dircolors/Cargo.toml +++ b/src/uu/dircolors/Cargo.toml @@ -16,7 +16,6 @@ path = "src/dircolors.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -glob = "0.3.0" uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } [[bin]] diff --git a/src/uu/vdir/Cargo.toml b/src/uu/vdir/Cargo.toml index b4328ed8d..d62b20b39 100644 --- a/src/uu/vdir/Cargo.toml +++ b/src/uu/vdir/Cargo.toml @@ -17,7 +17,6 @@ path = "src/vdir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } -selinux = { version="0.3", optional = true } uu_ls = { version = ">=0.0.16", path="../ls"} [[bin]] From c44c7ac7b288b9dc8110985a6f56f193fd634a66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Nov 2022 06:07:50 +0000 Subject: [PATCH 54/60] build(deps): bump num_cpus from 1.13.1 to 1.14.0 Bumps [num_cpus](https://github.com/seanmonstar/num_cpus) from 1.13.1 to 1.14.0. - [Release notes](https://github.com/seanmonstar/num_cpus/releases) - [Changelog](https://github.com/seanmonstar/num_cpus/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/num_cpus/compare/v1.13.1...v1.14.0) --- updated-dependencies: - dependency-name: num_cpus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/nproc/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd09545da..87ac0034f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1342,9 +1342,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index 057062a73..45c1dd81f 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nproc.rs" [dependencies] libc = "0.2.137" -num_cpus = "1.10" +num_cpus = "1.14" clap = { version = "4.0", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } From 59f37d88d017ba613fe90933f560b29f0d088d3d Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 4 Nov 2022 08:54:51 +0100 Subject: [PATCH 55/60] rm: fix "needless borrow" clippy warnings --- src/uu/rm/src/rm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index f65ebb2fa..5be19893b 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -170,7 +170,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_PROMPT) .short('i') .help("prompt before every removal") - .overrides_with_all(&[OPT_PROMPT_MORE, OPT_INTERACTIVE]) + .overrides_with_all([OPT_PROMPT_MORE, OPT_INTERACTIVE]) .action(ArgAction::SetTrue), ) .arg( @@ -178,7 +178,7 @@ pub fn uu_app() -> Command { .short('I') .help("prompt once before removing more than three files, or when removing recursively. \ Less intrusive than -i, while still giving some protection against most mistakes") - .overrides_with_all(&[OPT_PROMPT, OPT_INTERACTIVE]) + .overrides_with_all([OPT_PROMPT, OPT_INTERACTIVE]) .action(ArgAction::SetTrue), ) .arg( @@ -189,7 +189,7 @@ pub fn uu_app() -> Command { prompts always", ) .value_name("WHEN") - .overrides_with_all(&[OPT_PROMPT, OPT_PROMPT_MORE]), + .overrides_with_all([OPT_PROMPT, OPT_PROMPT_MORE]), ) .arg( Arg::new(OPT_ONE_FILE_SYSTEM) From 96ef306cb34bb1cfb9a920065fa47f34d84f1810 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 4 Nov 2022 09:11:24 +0100 Subject: [PATCH 56/60] Fix "unwrap or else default" clippy warning --- src/uucore/src/lib/features/fsext.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index f306f34de..68e2b7a55 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -303,7 +303,7 @@ impl MountInfo { let mut mn_info = Self { dev_id: volume_name, dev_name, - fs_type: fs_type.unwrap_or_else(|| "".to_string()), + fs_type: fs_type.unwrap_or_default(), mount_root, mount_dir: "".to_string(), mount_option: "".to_string(), From 7df36bb1538cb97207e8ff2a16402453a40cd45f Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 4 Nov 2022 09:52:09 +0100 Subject: [PATCH 57/60] mv: fix "needless borrow" clippy warnings --- src/uu/mv/src/mv.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index 4697fac4a..671aea0ad 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -475,11 +475,11 @@ fn rename_symlink_fallback(from: &Path, to: &Path) -> io::Result<()> { { if path_symlink_points_to.exists() { if path_symlink_points_to.is_dir() { - windows::fs::symlink_dir(&path_symlink_points_to, &to)?; + windows::fs::symlink_dir(&path_symlink_points_to, to)?; } else { - windows::fs::symlink_file(&path_symlink_points_to, &to)?; + windows::fs::symlink_file(&path_symlink_points_to, to)?; } - fs::remove_file(&from)?; + fs::remove_file(from)?; } else { return Err(io::Error::new( io::ErrorKind::NotFound, From 8114abc95659e4e94b8e2216dc8131aa57d3852b Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 4 Nov 2022 11:10:35 +0100 Subject: [PATCH 58/60] Fix "needless borrow" clippy warning in env test --- tests/by-util/test_env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 3172320f3..9b6452548 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -220,7 +220,7 @@ fn test_change_directory() { let out = scene .ucmd() .arg("--chdir") - .arg(&temporary_path) + .arg(temporary_path) .args(&pwd) .succeeds() .stdout_move_str(); From be49eb68f30e7f215b194369c029a6bb5aabf40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Fri, 4 Nov 2022 13:35:54 +0300 Subject: [PATCH 59/60] fix: address test failures --- src/uu/sync/src/sync.rs | 11 +++++++++-- tests/by-util/test_sync.rs | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 08ba6b1d4..0fa81218a 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -11,6 +11,8 @@ extern crate libc; use clap::{crate_version, Arg, ArgAction, Command}; #[cfg(any(target_os = "linux", target_os = "android"))] +use nix::errno::Errno; +#[cfg(any(target_os = "linux", target_os = "android"))] use nix::fcntl::{open, OFlag}; #[cfg(any(target_os = "linux", target_os = "android"))] use nix::sys::stat::Mode; @@ -170,9 +172,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // Use the Nix open to be able to set the NONBLOCK flags for fifo files #[cfg(any(target_os = "linux", target_os = "android"))] { - open(Path::new(&f), OFlag::O_NONBLOCK, Mode::empty()) - .map_err_context(|| format!("cannot stat {}", f.quote()))?; + let path = Path::new(&f); + if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) { + if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) { + return e.map_err_context(|| format!("cannot stat {}", f.quote()))?; + } + } } + #[cfg(not(any(target_os = "linux", target_os = "android")))] { if !Path::new(&f).exists() { diff --git a/tests/by-util/test_sync.rs b/tests/by-util/test_sync.rs index 7f2cd4b66..4bf2629c4 100644 --- a/tests/by-util/test_sync.rs +++ b/tests/by-util/test_sync.rs @@ -64,9 +64,9 @@ fn test_sync_no_permission_dir() { ts.ccmd("chmod").arg("0").arg(dir).succeeds(); let result = ts.ucmd().arg("--data").arg(dir).fails(); - result.stderr_contains("sync: error opening 'foo': Permission denied"); + result.stderr_contains("sync: cannot stat 'foo': Permission denied"); let result = ts.ucmd().arg(dir).fails(); - result.stderr_contains("sync: error opening 'foo': Permission denied"); + result.stderr_contains("sync: cannot stat 'foo': Permission denied"); } #[cfg(not(target_os = "windows"))] From 5b100fef62af741114a51d296e6c1d251fc320b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sun, 9 Oct 2022 23:22:36 -0400 Subject: [PATCH 60/60] cp: implement --copy-contents option for fifos Implement the `--copy-contents` option when the source is a FIFO, so that the contents of the FIFO are copied (when the bytes become available for reading) instead of the FIFO object itself. For example, $ mkfifo fifo $ cp --copy-contents fifo outfile & [1] 1614080 $ echo foo > fifo $ cat outfile foo [1]+ Done cp --copy-contents fifo outfile --- src/uu/cp/src/cp.rs | 5 +-- src/uu/cp/src/platform/linux.rs | 55 +++++++++++++++++++++++---------- src/uu/cp/src/platform/macos.rs | 18 +++++++++-- tests/by-util/test_cp.rs | 31 ++++++++++++++++++- 4 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 3a1697039..2b9cea233 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -677,7 +677,6 @@ fn add_all_attributes() -> Vec { impl Options { fn from_matches(matches: &ArgMatches) -> CopyResult { let not_implemented_opts = vec![ - options::COPY_CONTENTS, #[cfg(not(any(windows, unix)))] options::ONE_FILE_SYSTEM, options::CONTEXT, @@ -1445,7 +1444,7 @@ fn copy_helper( * https://github.com/rust-lang/rust/issues/79390 */ File::create(dest).context(dest.display().to_string())?; - } else if source_is_fifo && options.recursive { + } else if source_is_fifo && options.recursive && !options.copy_contents { #[cfg(unix)] copy_fifo(dest, options.overwrite)?; } else if source_is_symlink { @@ -1457,6 +1456,8 @@ fn copy_helper( options.reflink_mode, options.sparse_mode, context, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))] + source_is_fifo, )?; } diff --git a/src/uu/cp/src/platform/linux.rs b/src/uu/cp/src/platform/linux.rs index 7f47b884a..4af897d3c 100644 --- a/src/uu/cp/src/platform/linux.rs +++ b/src/uu/cp/src/platform/linux.rs @@ -21,29 +21,39 @@ macro_rules! FICLONE { }; } +/// The fallback behavior for [`clone`] on failed system call. +#[derive(Clone, Copy)] +enum CloneFallback { + /// Raise an error. + Error, + + /// Use [`std::io::copy`]. + IOCopy, + + /// Use [`std::fs::copy`]. + FSCopy, +} + /// Use the Linux `ioctl_ficlone` API to do a copy-on-write clone. /// -/// If `fallback` is true and there is a failure performing the clone, -/// then this function performs a standard [`std::fs::copy`]. Otherwise, -/// this function returns an error. +/// `fallback` controls what to do if the system call fails. #[cfg(any(target_os = "linux", target_os = "android"))] -fn clone

(source: P, dest: P, fallback: bool) -> std::io::Result<()> +fn clone

(source: P, dest: P, fallback: CloneFallback) -> std::io::Result<()> where P: AsRef, { - let src_file = File::open(&source)?; - let dst_file = File::create(&dest)?; + let mut src_file = File::open(&source)?; + let mut dst_file = File::create(&dest)?; let src_fd = src_file.as_raw_fd(); let dst_fd = dst_file.as_raw_fd(); let result = unsafe { libc::ioctl(dst_fd, FICLONE!(), src_fd) }; - if result != 0 { - if fallback { - std::fs::copy(source, dest).map(|_| ()) - } else { - Err(std::io::Error::last_os_error()) - } - } else { - Ok(()) + if result == 0 { + return Ok(()); + } + match fallback { + CloneFallback::Error => Err(std::io::Error::last_os_error()), + CloneFallback::IOCopy => std::io::copy(&mut src_file, &mut dst_file).map(|_| ()), + CloneFallback::FSCopy => std::fs::copy(source, dest).map(|_| ()), } } @@ -89,18 +99,31 @@ where } /// Copies `source` to `dest` using copy-on-write if possible. +/// +/// The `source_is_fifo` flag must be set to `true` if and only if +/// `source` is a FIFO (also known as a named pipe). In this case, +/// copy-on-write is not possible, so we copy the contents using +/// [`std::io::copy`]. pub(crate) fn copy_on_write( source: &Path, dest: &Path, reflink_mode: ReflinkMode, sparse_mode: SparseMode, context: &str, + source_is_fifo: bool, ) -> CopyResult<()> { let result = match (reflink_mode, sparse_mode) { (ReflinkMode::Never, _) => std::fs::copy(source, dest).map(|_| ()), (ReflinkMode::Auto, SparseMode::Always) => sparse_copy(source, dest), - (ReflinkMode::Auto, _) => clone(source, dest, true), - (ReflinkMode::Always, SparseMode::Auto) => clone(source, dest, false), + + (ReflinkMode::Auto, _) => { + if source_is_fifo { + clone(source, dest, CloneFallback::IOCopy) + } else { + clone(source, dest, CloneFallback::FSCopy) + } + } + (ReflinkMode::Always, SparseMode::Auto) => clone(source, dest, CloneFallback::Error), (ReflinkMode::Always, _) => { return Err("`--reflink=always` can be used only with --sparse=auto".into()) } diff --git a/src/uu/cp/src/platform/macos.rs b/src/uu/cp/src/platform/macos.rs index 7f1524154..1185b7f7d 100644 --- a/src/uu/cp/src/platform/macos.rs +++ b/src/uu/cp/src/platform/macos.rs @@ -4,7 +4,8 @@ // * file that was distributed with this source code. // spell-checker:ignore reflink use std::ffi::CString; -use std::fs; +use std::fs::{self, File}; +use std::io; use std::os::unix::ffi::OsStrExt; use std::path::Path; @@ -13,12 +14,16 @@ use quick_error::ResultExt; use crate::{CopyResult, ReflinkMode, SparseMode}; /// Copies `source` to `dest` using copy-on-write if possible. +/// +/// The `source_is_fifo` flag must be set to `true` if and only if +/// `source` is a FIFO (also known as a named pipe). pub(crate) fn copy_on_write( source: &Path, dest: &Path, reflink_mode: ReflinkMode, sparse_mode: SparseMode, context: &str, + source_is_fifo: bool, ) -> CopyResult<()> { if sparse_mode != SparseMode::Auto { return Err("--sparse is only supported on linux".to_string().into()); @@ -65,8 +70,15 @@ pub(crate) fn copy_on_write( format!("failed to clone {:?} from {:?}: {}", source, dest, error).into(), ) } - ReflinkMode::Auto => fs::copy(source, dest).context(context)?, - ReflinkMode::Never => fs::copy(source, dest).context(context)?, + _ => { + if source_is_fifo { + let mut src_file = File::open(source)?; + let mut dst_file = File::create(dest)?; + io::copy(&mut src_file, &mut dst_file).context(context)? + } else { + fs::copy(source, dest).context(context)? + } + } }; } diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 8285905c5..e1ccdfb09 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs ROOTDIR USERDIR procfs +// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs ROOTDIR USERDIR procfs outfile use crate::common::util::*; #[cfg(not(windows))] @@ -2226,3 +2226,32 @@ fn test_copy_dir_preserve_permissions_inaccessible_file() { let metadata2 = at.metadata("d2"); assert_metadata_eq!(metadata1, metadata2); } + +/// Test for copying the contents of a FIFO as opposed to the FIFO object itself. +#[cfg(unix)] +#[test] +fn test_copy_contents_fifo() { + let scenario = TestScenario::new(util_name!()); + let at = &scenario.fixtures; + + // Start the `cp` process, reading the contents of `fifo` and + // writing to regular file `outfile`. + at.mkfifo("fifo"); + let mut ucmd = scenario.ucmd(); + let child = ucmd + .args(&["--copy-contents", "fifo", "outfile"]) + .run_no_wait(); + + // Write some bytes to the `fifo`. We expect these bytes to get + // copied through to `outfile`. + std::fs::write(at.plus("fifo"), "foo").unwrap(); + + // At this point the child process should have terminated + // successfully with no output. The `outfile` should have the + // contents of `fifo` copied into it. + let output = child.wait_with_output().unwrap(); + assert!(output.status.success()); + assert!(output.stdout.is_empty()); + assert!(output.stderr.is_empty()); + assert_eq!(at.read("outfile"), "foo"); +}