From a5863e8dc49ea2791b26fd8dc1057b7467cedf41 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 14 Sep 2026 15:15:11 +0200 Subject: [PATCH] date: allow non-utf8 path for --reference --- src/uu/date/src/date.rs | 8 +++++--- tests/by-util/test_date.rs | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index d4a23b19a2..74c03a56be 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -15,6 +15,7 @@ use jiff::{Timestamp, Zoned}; use parse_datetime::{ExtendedDateTime, ParsedDateTime}; use std::borrow::Cow; use std::collections::HashMap; +use std::ffi::OsString; use std::fs::File; use std::io::{BufRead, BufReader, BufWriter, Read, Write, stderr}; use std::path::PathBuf; @@ -343,7 +344,7 @@ fn parse_military_timezone_with_offset(s: &str) -> Option<(i32, DayDelta)> { pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?; - let date_source = if let Some(date_os) = matches.get_one::(OPT_DATE) { + let date_source = if let Some(date_os) = matches.get_one::(OPT_DATE) { // Convert OsString to String, handling invalid UTF-8 with GNU-compatible error let date = date_os.to_str().ok_or_else(|| { let bytes = date_os.as_encoded_bytes(); @@ -356,7 +357,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { "-" => DateSource::Stdin, _ => DateSource::File(file.into()), } - } else if let Some(file) = matches.get_one::(OPT_REFERENCE) { + } else if let Some(file) = matches.get_one::(OPT_REFERENCE) { DateSource::FileMtime(file.into()) } else if matches.get_flag(OPT_RESOLUTION) { DateSource::Resolution @@ -691,7 +692,7 @@ pub fn uu_app() -> Command { .value_name("STRING") .allow_hyphen_values(true) .overrides_with(OPT_DATE) - .value_parser(clap::value_parser!(std::ffi::OsString)) + .value_parser(clap::value_parser!(OsString)) .help(translate!("date-help-date")), ) .arg( @@ -752,6 +753,7 @@ pub fn uu_app() -> Command { .long(OPT_REFERENCE) .value_name("FILE") .value_hint(clap::ValueHint::AnyPath) + .value_parser(clap::value_parser!(OsString)) .conflicts_with_all([OPT_DATE, OPT_FILE, OPT_RESOLUTION]) .overrides_with(OPT_REFERENCE) .help(translate!("date-help-reference")), diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 5f35c5d67b..b050f4d4f3 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -700,6 +700,27 @@ fn test_date_for_file_mtime() { .stdout_only("1234\n"); } +#[test] +#[cfg(target_os = "linux")] +#[cfg_attr(wasi_runner, ignore = "WASI: argv/filenames must be valid UTF-8")] +fn test_date_reference_is_non_utf8_path() { + use std::os::unix::ffi::OsStrExt; + use std::time::{Duration, UNIX_EPOCH}; + + let (at, mut ucmd) = at_and_ucmd!(); + + let reference_file = std::ffi::OsStr::from_bytes(b"reference_\xFF\xFE.txt"); + let f = std::fs::File::create(at.plus(reference_file)).unwrap(); + let modification_date = UNIX_EPOCH.checked_add(Duration::from_secs(1234)).unwrap(); + f.set_modified(modification_date).unwrap(); + + ucmd.arg("--reference") + .arg(reference_file) + .arg("+%s") + .succeeds() + .stdout_only("1234\n"); +} + #[test] fn test_date_multiple_references() { use std::time::{Duration, UNIX_EPOCH};