diff --git a/src/uu/shred/src/shred.rs b/src/uu/shred/src/shred.rs index c158678a4..b7b882c26 100644 --- a/src/uu/shred/src/shred.rs +++ b/src/uu/shred/src/shred.rs @@ -9,6 +9,7 @@ use clap::{Arg, ArgAction, Command}; #[cfg(unix)] use libc::S_IWUSR; use rand::{Rng, SeedableRng, rngs::StdRng, seq::SliceRandom}; +use std::ffi::OsString; use std::fs::{self, File, OpenOptions}; use std::io::{self, Read, Seek, Write}; #[cfg(unix)] @@ -297,7 +298,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let zero = matches.get_flag(options::ZERO); let verbose = matches.get_flag(options::VERBOSE); - for path_str in matches.get_many::(options::FILE).unwrap() { + for path_str in matches.get_many::(options::FILE).unwrap() { show_if_err!(wipe_file( path_str, iterations, @@ -396,7 +397,8 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::FILE) .action(ArgAction::Append) - .value_hint(clap::ValueHint::FilePath), + .value_hint(clap::ValueHint::FilePath) + .value_parser(clap::value_parser!(OsString)), ) } @@ -428,7 +430,7 @@ fn pass_name(pass_type: &PassType) -> String { #[allow(clippy::too_many_arguments)] #[allow(clippy::cognitive_complexity)] fn wipe_file( - path_str: &str, + path_str: &OsString, n_passes: usize, remove_method: RemoveMethod, size: Option, @@ -605,7 +607,7 @@ fn do_pass( /// Repeatedly renames the file with strings of decreasing length (most likely all 0s) /// Return the path of the file after its last renaming or None in case of an error fn wipe_name(orig_path: &Path, verbose: bool, remove_method: RemoveMethod) -> Option { - let file_name_len = orig_path.file_name().unwrap().to_str().unwrap().len(); + let file_name_len = orig_path.file_name().unwrap().len(); let mut last_path = PathBuf::from(orig_path); @@ -657,7 +659,7 @@ fn wipe_name(orig_path: &Path, verbose: bool, remove_method: RemoveMethod) -> Op fn do_remove( path: &Path, - orig_filename: &str, + orig_filename: &OsString, verbose: bool, remove_method: RemoveMethod, ) -> Result<(), io::Error> { diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index a31ef4bf4..ad8f79200 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -316,3 +316,26 @@ fn test_shred_rename_exhaustion() { assert!(!at.file_exists("test")); } + +#[test] +#[cfg(target_os = "linux")] +fn test_shred_non_utf8_paths() { + use std::fs; + + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + // Create test file with non-UTF-8 name + at.write("temp.txt", "test content"); + + #[cfg(unix)] + { + use std::os::unix::ffi::OsStrExt; + let file_name = std::ffi::OsStr::from_bytes(b"test_\xFF\xFE.txt"); + + fs::rename(at.subdir.join("temp.txt"), at.subdir.join(file_name)).unwrap(); + + // Test that shred can handle non-UTF-8 filenames + ts.ucmd().arg(file_name).succeeds(); + } +}