diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 451b5b560..7354c20c9 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -157,7 +157,7 @@ fn is_first_filename_timestamp( reference: Option<&OsString>, date: Option<&str>, timestamp: Option<&str>, - files: &[&String], + files: &[&OsString], ) -> bool { if timestamp.is_none() && reference.is_none() @@ -166,8 +166,11 @@ fn is_first_filename_timestamp( // env check is last as the slowest op && matches!(std::env::var("_POSIX2_VERSION").as_deref(), Ok("199209")) { - let s = files[0]; - all_digits(s) && (s.len() == 8 || (s.len() == 10 && (69..=99).contains(&get_year(s)))) + if let Some(s) = files[0].to_str() { + all_digits(s) && (s.len() == 8 || (s.len() == 10 && (69..=99).contains(&get_year(s)))) + } else { + false + } } else { false } @@ -189,8 +192,8 @@ fn shr2(s: &str) -> String { pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().get_matches_from_localized(args); - let mut filenames: Vec<&String> = matches - .get_many::(ARG_FILES) + let mut filenames: Vec<&OsString> = matches + .get_many::(ARG_FILES) .ok_or_else(|| { USimpleError::new( 1, @@ -211,12 +214,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(|t| t.to_owned()); if is_first_filename_timestamp(reference, date.as_deref(), timestamp.as_deref(), &filenames) { - timestamp = if filenames[0].len() == 10 { - Some(shr2(filenames[0])) - } else { - Some(filenames[0].to_string()) - }; - filenames = filenames[1..].to_vec(); + if let Some(first_file) = filenames[0].to_str() { + timestamp = if first_file.len() == 10 { + Some(shr2(first_file)) + } else { + Some(first_file.to_string()) + }; + filenames = filenames[1..].to_vec(); + } } let source = if let Some(reference) = reference { @@ -338,6 +343,7 @@ pub fn uu_app() -> Command { Arg::new(ARG_FILES) .action(ArgAction::Append) .num_args(1..) + .value_parser(clap::value_parser!(OsString)) .value_hint(clap::ValueHint::AnyPath), ) .group( diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 6c2d3ff1b..88c91ebcb 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -1013,3 +1013,26 @@ fn test_touch_f_option() { assert!(at.file_exists(file)); at.remove(file); } + +#[test] +#[cfg(target_os = "linux")] +fn test_touch_non_utf8_paths() { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + // Create a test file with non-UTF-8 bytes in the name + let non_utf8_bytes = b"test_\xFF\xFE.txt"; + let non_utf8_name = OsStr::from_bytes(non_utf8_bytes); + + // Test that touch handles non-UTF-8 file names without crashing + let result = scene.ucmd().arg(non_utf8_name).succeeds(); + + // Verify no output and file was created + result.no_output(); + + // Check that the file was created (using the raw path) + assert!(std::fs::metadata(at.plus(non_utf8_name)).is_ok()); +}