From d823d2e5cd2fe4be8d3c84e861466792fb257a16 Mon Sep 17 00:00:00 2001 From: Francesco Pio Gaglione Date: Mon, 8 Jun 2026 23:48:19 +0200 Subject: [PATCH 1/2] shred: fix error message when path has trailing slash --- src/uu/shred/locales/en-US.ftl | 1 + src/uu/shred/locales/fr-FR.ftl | 1 + src/uu/shred/src/shred.rs | 6 ++++++ tests/by-util/test_shred.rs | 12 ++++++++++++ 4 files changed, 20 insertions(+) diff --git a/src/uu/shred/locales/en-US.ftl b/src/uu/shred/locales/en-US.ftl index 41af9150ad7..9f551dbea91 100644 --- a/src/uu/shred/locales/en-US.ftl +++ b/src/uu/shred/locales/en-US.ftl @@ -42,6 +42,7 @@ shred-invalid-number-of-passes = invalid number of passes: {$passes} shred-cannot-open-random-source = cannot open random source: {$source} shred-invalid-file-size = invalid file size: {$size} shred-no-such-file-or-directory = {$file}: No such file or directory +shred-failed-to-open-writing-not-dir = failed to open for writing: Not a directory shred-not-a-file = {$file}: Not a file # Option help text diff --git a/src/uu/shred/locales/fr-FR.ftl b/src/uu/shred/locales/fr-FR.ftl index aa248254a35..6a9d1e1209f 100644 --- a/src/uu/shred/locales/fr-FR.ftl +++ b/src/uu/shred/locales/fr-FR.ftl @@ -41,6 +41,7 @@ shred-invalid-number-of-passes = nombre de passes invalide : {$passes} shred-cannot-open-random-source = impossible d'ouvrir la source aléatoire : {$source} shred-invalid-file-size = taille de fichier invalide : {$size} shred-no-such-file-or-directory = {$file} : Aucun fichier ou répertoire de ce type +shred-failed-to-open-writing-not-dir = Impossible d'ouvrir le répertoire en écriture : Ce n'est pas un répertoire shred-not-a-file = {$file} : N'est pas un fichier # Texte d'aide des options diff --git a/src/uu/shred/src/shred.rs b/src/uu/shred/src/shred.rs index d382a999387..89de56e8130 100644 --- a/src/uu/shred/src/shred.rs +++ b/src/uu/shred/src/shred.rs @@ -625,6 +625,12 @@ fn wipe_file( ) -> UResult<()> { // Get these potential errors out of the way first let path = Path::new(path_str); + if !path.is_file() { + return Err(USimpleError::new( + 1, + translate!("shred-failed-to-open-writing-not-dir"), + )); + } if !path.exists() { return Err(USimpleError::new( 1, diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index 43327fe0e8e..cc2c88487dc 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -434,3 +434,15 @@ fn test_gnu_shred_passes_different_counts() { result.stderr_contains("pass 1/19 (random)"); result.stderr_contains("pass 19/19 (random)"); } + +#[test] +fn test_shred_trailing_slash_on_file() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("a"); + scene + .ucmd() + .arg("a/") + .fails() + .stderr_contains("Not a directory"); +} From d95d271ea732e9919ce75e363447d9dd13643daa Mon Sep 17 00:00:00 2001 From: Francesco Pio Gaglione Date: Wed, 10 Jun 2026 17:49:21 +0200 Subject: [PATCH 2/2] Improve error handling for trailing slashes in shred --- src/uu/shred/locales/en-US.ftl | 3 ++- src/uu/shred/locales/fr-FR.ftl | 3 ++- src/uu/shred/src/shred.rs | 20 +++++++++++++++----- tests/by-util/test_shred.rs | 12 ++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/uu/shred/locales/en-US.ftl b/src/uu/shred/locales/en-US.ftl index 9f551dbea91..b2f749a0b82 100644 --- a/src/uu/shred/locales/en-US.ftl +++ b/src/uu/shred/locales/en-US.ftl @@ -42,7 +42,8 @@ shred-invalid-number-of-passes = invalid number of passes: {$passes} shred-cannot-open-random-source = cannot open random source: {$source} shred-invalid-file-size = invalid file size: {$size} shred-no-such-file-or-directory = {$file}: No such file or directory -shred-failed-to-open-writing-not-dir = failed to open for writing: Not a directory +shred-failed-to-open-for-writing-not-a-directory = {$file}: failed to open for writing: Not a directory +shred-failed-to-open-for-writing-is-a-directory = {$file}: failed to open for writing: Is a directory shred-not-a-file = {$file}: Not a file # Option help text diff --git a/src/uu/shred/locales/fr-FR.ftl b/src/uu/shred/locales/fr-FR.ftl index 6a9d1e1209f..d03b9d74ad8 100644 --- a/src/uu/shred/locales/fr-FR.ftl +++ b/src/uu/shred/locales/fr-FR.ftl @@ -41,7 +41,8 @@ shred-invalid-number-of-passes = nombre de passes invalide : {$passes} shred-cannot-open-random-source = impossible d'ouvrir la source aléatoire : {$source} shred-invalid-file-size = taille de fichier invalide : {$size} shred-no-such-file-or-directory = {$file} : Aucun fichier ou répertoire de ce type -shred-failed-to-open-writing-not-dir = Impossible d'ouvrir le répertoire en écriture : Ce n'est pas un répertoire +shred-failed-to-open-for-writing-not-a-directory = {$file} : impossible d'ouvrir en écriture : N'est pas un répertoire +shred-failed-to-open-for-writing-is-a-directory = {$file} : impossible d'ouvrir en écriture : Est un répertoire shred-not-a-file = {$file} : N'est pas un fichier # Texte d'aide des options diff --git a/src/uu/shred/src/shred.rs b/src/uu/shred/src/shred.rs index 89de56e8130..69bf981f1bd 100644 --- a/src/uu/shred/src/shred.rs +++ b/src/uu/shred/src/shred.rs @@ -625,12 +625,22 @@ fn wipe_file( ) -> UResult<()> { // Get these potential errors out of the way first let path = Path::new(path_str); - if !path.is_file() { - return Err(USimpleError::new( - 1, - translate!("shred-failed-to-open-writing-not-dir"), - )); + + if path_str.as_encoded_bytes().ends_with(b"/") { + if path.is_dir() { + return Err(USimpleError::new( + 1, + translate!("shred-failed-to-open-for-writing-is-a-directory", "file" => path.maybe_quote()), + )); + } + if fs::metadata(path).is_err_and(|e| e.kind() == io::ErrorKind::NotADirectory) { + return Err(USimpleError::new( + 1, + translate!("shred-failed-to-open-for-writing-not-a-directory", "file" => path.maybe_quote()), + )); + } } + if !path.exists() { return Err(USimpleError::new( 1, diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index cc2c88487dc..28812b106f4 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -446,3 +446,15 @@ fn test_shred_trailing_slash_on_file() { .fails() .stderr_contains("Not a directory"); } + +#[test] +fn test_shred_trailing_slash_on_dir() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("d"); + scene + .ucmd() + .arg("d/") + .fails() + .stderr_contains("Is a directory"); +}