From df3816e2858337b8f2ca1e29eaefb0a4a4a4a5ab Mon Sep 17 00:00:00 2001 From: cerdelen Date: Mon, 12 Jan 2026 18:19:23 +0100 Subject: [PATCH 1/6] rm: Enforce full --no-preserve-root flag (no abbreviation) --- src/uu/rm/locales/en-US.ftl | 1 + src/uu/rm/locales/fr-FR.ftl | 1 + src/uu/rm/src/rm.rs | 13 ++++++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/uu/rm/locales/en-US.ftl b/src/uu/rm/locales/en-US.ftl index 12816693e69..2d4486ce2fe 100644 --- a/src/uu/rm/locales/en-US.ftl +++ b/src/uu/rm/locales/en-US.ftl @@ -43,6 +43,7 @@ rm-error-dangerous-recursive-operation = it is dangerous to operate recursively rm-error-use-no-preserve-root = use --no-preserve-root to override this failsafe rm-error-refusing-to-remove-directory = refusing to remove '.' or '..' directory: skipping {$path} rm-error-cannot-remove = cannot remove {$file} +rm-error-may-not-abbreviate-no-preserve-root = you may not abbreviate the --no-preserve-root option # Verbose messages rm-verbose-removed = removed {$file} diff --git a/src/uu/rm/locales/fr-FR.ftl b/src/uu/rm/locales/fr-FR.ftl index e1ee8ec2314..52d881d0266 100644 --- a/src/uu/rm/locales/fr-FR.ftl +++ b/src/uu/rm/locales/fr-FR.ftl @@ -43,6 +43,7 @@ rm-error-dangerous-recursive-operation = il est dangereux d'opérer récursiveme rm-error-use-no-preserve-root = utilisez --no-preserve-root pour outrepasser cette protection rm-error-refusing-to-remove-directory = refus de supprimer le répertoire '.' ou '..' : ignorer {$path} rm-error-cannot-remove = impossible de supprimer {$file} +rm-error-may-not-abbreviate-no-preserve-root = Vous ne pouvez pas abréger l'option --no-preserve-root # Messages verbeux rm-verbose-removed = {$file} supprimé diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 55c5b932f96..45f263d2a66 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -45,6 +45,8 @@ enum RmError { UseNoPreserveRoot, #[error("{}", translate!("rm-error-refusing-to-remove-directory", "path" => _0.quote()))] RefusingToRemoveDirectory(OsString), + #[error("{}", translate!("rm-error-may-not-abbreviate-no-preserve-root"))] + MayNotAbbreviateNoPreserveRoot, } impl UError for RmError {} @@ -200,7 +202,16 @@ static ARG_FILES: &str = "files"; #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?; + let args = args.collect_ignore(); + let matches = uucore::clap_localization::handle_clap_result(uu_app(), args.iter())?; + + // manually parse all args to verify --no-preserve-root did not get abbreviated (clap does + // allow this) + if matches.get_flag(OPT_NO_PRESERVE_ROOT) { + if !args.iter().any(|arg| arg == "--no-preserve-root") { + return Err(RmError::MayNotAbbreviateNoPreserveRoot.into()); + } + } let files: Vec<_> = matches .get_many::(ARG_FILES) From e1de2468bdbff7b57acbf43193281c4d8b33bc33 Mon Sep 17 00:00:00 2001 From: cerdelen Date: Mon, 12 Jan 2026 18:19:46 +0100 Subject: [PATCH 2/6] rm: regression test no abbreviated --no-preserve-root flag --- tests/by-util/test_rm.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 38230f2ad36..a701ac24de5 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -1217,3 +1217,31 @@ fn test_progress_no_output_on_error() { .stderr_contains("cannot remove") .stderr_contains("No such file or directory"); } + +#[test] +fn no_preserve_root_may_not_be_abbreviated() { + let (at, _ucmd) = at_and_ucmd!(); + let file = "test_file_123"; + + at.touch(file); + + new_ucmd!() + .arg("--n") + .arg(file) + .fails() + .stderr_contains(format!("you may not abbreviate the --no-preserve-root option")); + + new_ucmd!() + .arg("--no-pre") + .arg(file) + .fails() + .stderr_contains(format!("you may not abbreviate the --no-preserve-root option")); + + new_ucmd!() + .arg("--no-preserve-ro") + .arg(file) + .fails() + .stderr_contains(format!("you may not abbreviate the --no-preserve-root option")); + + assert!(at.file_exists(file)); +} From db9d758b3ea716df38365ad0e6d4856d14ffd90e Mon Sep 17 00:00:00 2001 From: cerdelen Date: Mon, 12 Jan 2026 18:22:30 +0100 Subject: [PATCH 3/6] cargo fmt + clippy --- src/uu/rm/src/rm.rs | 7 +++---- tests/by-util/test_rm.rs | 12 +++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 45f263d2a66..aa6e99fb7e9 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -207,10 +207,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // manually parse all args to verify --no-preserve-root did not get abbreviated (clap does // allow this) - if matches.get_flag(OPT_NO_PRESERVE_ROOT) { - if !args.iter().any(|arg| arg == "--no-preserve-root") { - return Err(RmError::MayNotAbbreviateNoPreserveRoot.into()); - } + if matches.get_flag(OPT_NO_PRESERVE_ROOT) && !args.iter().any(|arg| arg == "--no-preserve-root") + { + return Err(RmError::MayNotAbbreviateNoPreserveRoot.into()); } let files: Vec<_> = matches diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index a701ac24de5..361924f7117 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -1229,19 +1229,25 @@ fn no_preserve_root_may_not_be_abbreviated() { .arg("--n") .arg(file) .fails() - .stderr_contains(format!("you may not abbreviate the --no-preserve-root option")); + .stderr_contains(format!( + "you may not abbreviate the --no-preserve-root option" + )); new_ucmd!() .arg("--no-pre") .arg(file) .fails() - .stderr_contains(format!("you may not abbreviate the --no-preserve-root option")); + .stderr_contains(format!( + "you may not abbreviate the --no-preserve-root option" + )); new_ucmd!() .arg("--no-preserve-ro") .arg(file) .fails() - .stderr_contains(format!("you may not abbreviate the --no-preserve-root option")); + .stderr_contains(format!( + "you may not abbreviate the --no-preserve-root option" + )); assert!(at.file_exists(file)); } From 698d4e5b2d779564803472a1524aedbf623325f1 Mon Sep 17 00:00:00 2001 From: cerdelen Date: Mon, 12 Jan 2026 18:45:26 +0100 Subject: [PATCH 4/6] rm: Ubuntu cargo clippy --- tests/by-util/test_rm.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 361924f7117..af4b598439c 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -1229,25 +1229,19 @@ fn no_preserve_root_may_not_be_abbreviated() { .arg("--n") .arg(file) .fails() - .stderr_contains(format!( - "you may not abbreviate the --no-preserve-root option" - )); + .stderr_contains("you may not abbreviate the --no-preserve-root option"); new_ucmd!() .arg("--no-pre") .arg(file) .fails() - .stderr_contains(format!( - "you may not abbreviate the --no-preserve-root option" - )); + .stderr_contains("you may not abbreviate the --no-preserve-root option"); new_ucmd!() .arg("--no-preserve-ro") .arg(file) .fails() - .stderr_contains(format!( - "you may not abbreviate the --no-preserve-root option" - )); + .stderr_contains("you may not abbreviate the --no-preserve-root option"); assert!(at.file_exists(file)); } From b370eeae9139e7777c4cb99070c1c041422e92a0 Mon Sep 17 00:00:00 2001 From: cerdelen Date: Mon, 12 Jan 2026 18:47:05 +0100 Subject: [PATCH 5/6] rm: Improve efficiency by checking later By checking later we can reuse the result of looking up the clap flag. Since this is a map lookup it's relatively inefficient so reusing the previous lookup should improve benchmark in most cases. --- src/uu/rm/src/rm.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index aa6e99fb7e9..ebb0aee15da 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -205,13 +205,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args.collect_ignore(); let matches = uucore::clap_localization::handle_clap_result(uu_app(), args.iter())?; - // manually parse all args to verify --no-preserve-root did not get abbreviated (clap does - // allow this) - if matches.get_flag(OPT_NO_PRESERVE_ROOT) && !args.iter().any(|arg| arg == "--no-preserve-root") - { - return Err(RmError::MayNotAbbreviateNoPreserveRoot.into()); - } - let files: Vec<_> = matches .get_many::(ARG_FILES) .map(|v| v.map(OsString::as_os_str).collect()) @@ -263,6 +256,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { None }, }; + + // manually parse all args to verify --no-preserve-root did not get abbreviated (clap does + // allow this) + if !options.preserve_root && !args.iter().any(|arg| arg == "--no-preserve-root") { + return Err(RmError::MayNotAbbreviateNoPreserveRoot.into()); + } + if options.interactive == InteractiveMode::Once && (options.recursive || files.len() > 3) { let msg: String = format!( "remove {} {}{}", From ca4fad50bcc3b00d1abbab80edf6be90ab71a130 Mon Sep 17 00:00:00 2001 From: Cedric Erdelen Date: Sun, 18 Jan 2026 20:25:22 +0100 Subject: [PATCH 6/6] rm: using OsString collect to have correct behaviour when non utf characters are present --- 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 fd701196986..252c723406b 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -202,7 +202,7 @@ static ARG_FILES: &str = "files"; #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let args = args.collect_ignore(); + let args: Vec = args.collect(); let matches = uucore::clap_localization::handle_clap_result(uu_app(), args.iter())?; let files: Vec<_> = matches