touch: fix handling of non-UTF-8 filenames

This commit is contained in:
Sylvestre Ledru
2025-08-14 10:52:24 +02:00
parent a3ebaaa730
commit c0da27addc
2 changed files with 40 additions and 11 deletions
+17 -11
View File
@@ -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::<String>(ARG_FILES)
let mut filenames: Vec<&OsString> = matches
.get_many::<OsString>(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(
+23
View File
@@ -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());
}