diff --git a/src/uu/shred/locales/en-US.ftl b/src/uu/shred/locales/en-US.ftl index b2f749a0b82..41af9150ad7 100644 --- a/src/uu/shred/locales/en-US.ftl +++ b/src/uu/shred/locales/en-US.ftl @@ -42,8 +42,6 @@ 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-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 d03b9d74ad8..aa248254a35 100644 --- a/src/uu/shred/locales/fr-FR.ftl +++ b/src/uu/shred/locales/fr-FR.ftl @@ -41,8 +41,6 @@ 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-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 c3e8bf40bb7..6387b5e9ddc 100644 --- a/src/uu/shred/src/shred.rs +++ b/src/uu/shred/src/shred.rs @@ -651,19 +651,18 @@ fn wipe_file( display_path }; - if path_str.as_encoded_bytes().ends_with(b"/") { - if path.is_dir() { - return Err(USimpleError::new( - 1, - translate_text!("shred-failed-to-open-for-writing-is-a-directory", "file" => display_path.maybe_quote()), - )); - } - if fs::metadata(path).is_err_and(|e| e.kind() == io::ErrorKind::NotADirectory) { - return Err(USimpleError::new( - 1, - translate_text!("shred-failed-to-open-for-writing-not-a-directory", "file" => display_path.maybe_quote()), - )); - } + if path_str.as_encoded_bytes().ends_with(b"/") + && let Err(e) = fs::metadata(path) + && e.kind() == io::ErrorKind::NotADirectory + { + return Err(USimpleError::new( + 1, + format!( + "{}: {}", + translate_text!("shred-failed-to-open-for-writing", "file" => display_path.maybe_quote()), + strip_errno(&e) + ), + )); } // On OpenBSD, /dev/fd/1 is a character device rather than a symlink. @@ -692,7 +691,8 @@ fn wipe_file( // "no such file" error while a permission error falls through to the // open-for-writing below, which surfaces the real reason. match get_metadata() { - Ok(md) if !md.is_file() => { + // Directories fall through so opening them for writing reports EISDIR. + Ok(md) if !md.is_file() && !md.is_dir() => { return Err(USimpleError::new( 1, translate_text!("shred-not-a-file", "file" => display_path.maybe_quote()), diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index 519c4ceca61..103c1fe4e97 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -467,23 +467,23 @@ 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"); + let result = scene.ucmd().arg("a/").fails(); + result.stderr_contains("a/: failed to open for writing: "); + // Windows reports this as "The directory name is invalid." + #[cfg(unix)] + result.stderr_contains("Not a directory"); } -#[test] -fn test_shred_trailing_slash_on_dir() { - let scene = TestScenario::new(util_name!()); - let at = &scene.fixtures; +#[rstest::rstest] +#[case("d")] +#[case("d/")] +#[cfg(unix)] +fn test_shred_on_dir(#[case] arg: &str) { + let (at, mut ucmd) = at_and_ucmd!(); at.mkdir("d"); - scene - .ucmd() - .arg("d/") - .fails() - .stderr_contains("Is a directory"); + ucmd.arg(arg).fails_with_code(1).stderr_only(format!( + "shred: {arg}: failed to open for writing: Is a directory\n" + )); } #[test] @@ -588,7 +588,7 @@ fn test_couldnt_rename() { #[rstest::rstest] #[case(&["1e3"], "shred: 1e3: No such file or directory\n")] -#[case(&["007"], "shred: 007: Not a file\n")] +#[case(&["007"], "shred: 007: failed to open for writing: Is a directory\n")] #[cfg(not(windows))] fn test_numeric_looking_file_names_are_kept_verbatim( #[case] args: &[&str],