diff --git a/deny.toml b/deny.toml index f659910e8..8154bbf90 100644 --- a/deny.toml +++ b/deny.toml @@ -64,7 +64,7 @@ highlight = "all" # spell-checker: disable skip = [ # getrandom - { name = "wasi", version="0.10.2+wasi-snapshot-preview1" }, + { name = "wasi", version="0.10.0+wasi-snapshot-preview1" }, # blake2d_simd { name = "arrayvec", version = "=0.7.2" }, # flimit/unix_socket diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 331867b5f..5264401ef 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -6,7 +6,7 @@ // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. -// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME subsecond +// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS pub extern crate filetime; #[macro_use] @@ -255,6 +255,41 @@ const POSIX_LOCALE_FORMAT: &[time::format_description::FormatItem] = format_desc const ISO_8601_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day]"); +// "%Y%m%d%H%M.%S" 15 chars +const YYYYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full][month repr:numerical padding:zero]\ + [day][hour][minute].[second]" +); + +// "%Y-%m-%d %H:%M:%S.%SS" 12 chars +const YYYYMMDDHHMMSS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full]-[month repr:numerical padding:zero]-\ + [day] [hour]:[minute]:[second].[subsecond]" +); +// "%Y-%m-%d %H:%M:%S" 12 chars +const YYYYMMDDHHMMS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full]-[month repr:numerical padding:zero]-\ + [day] [hour]:[minute]:[second]" +); + +// "%Y%m%d%H%M" 12 chars +const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full][month repr:numerical padding:zero]\ + [day][hour][minute]" +); + +// "%y%m%d%H%M.%S" 13 chars +const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:last_two padding:none][month][day]\ + [hour][minute].[second]" +); + +// "%y%m%d%H%M" 10 chars +const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:last_two padding:none][month padding:zero][day padding:zero]\ + [hour repr:24 padding:zero][minute padding:zero]" +); + fn parse_date(s: &str) -> UResult { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm @@ -269,8 +304,17 @@ fn parse_date(s: &str) -> UResult { // which is equivalent to the POSIX locale: %a %b %e %H:%M:%S %Y // Tue Dec 3 ... // ("%c", POSIX_LOCALE_FORMAT), - if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &POSIX_LOCALE_FORMAT) { - return Ok(local_dt_to_filetime(to_local(parsed))); + // + // But also support other format found in the GNU tests like + // in tests/misc/stat-nanoseconds.sh + for fmt in [ + POSIX_LOCALE_FORMAT, + YYYYMMDDHHMMS_FORMAT, + YYYYMMDDHHMMSS_FORMAT, + ] { + if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &fmt) { + return Ok(local_dt_to_filetime(to_local(parsed))); + } } // "Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)" @@ -294,30 +338,6 @@ fn parse_date(s: &str) -> UResult { Err(USimpleError::new(1, format!("Unable to parse date: {}", s))) } -// "%Y%m%d%H%M.%S" 15 chars -const YYYYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:full][month repr:numerical padding:zero]\ - [day][hour][minute].[second]" -); - -// "%Y%m%d%H%M" 12 chars -const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:full][month repr:numerical padding:zero]\ - [day][hour][minute]" -); - -// "%y%m%d%H%M.%S" 13 chars -const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:last_two padding:none][month][day]\ - [hour][minute].[second]" -); - -// "%y%m%d%H%M" 10 chars -const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:last_two padding:none][month padding:zero][day padding:zero]\ - [hour repr:24 padding:zero][minute padding:zero]" -); - fn parse_timestamp(s: &str) -> UResult { // TODO: handle error let now = time::OffsetDateTime::now_utc(); diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index d23fb090e..ed62692f4 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -427,6 +427,42 @@ fn test_touch_set_date3() { assert_eq!(mtime, expected); } +#[test] +fn test_touch_set_date4() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_set_date"; + + ucmd.args(&["-d", "1970-01-01 18:43:33", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let expected = FileTime::from_unix_time(60213, 0); + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + +#[test] +fn test_touch_set_date5() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_set_date"; + + ucmd.args(&["-d", "1970-01-01 18:43:33.023456789", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let expected = FileTime::from_unix_time(60213, 023456789); + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + #[test] fn test_touch_set_date_wrong_format() { let (_at, mut ucmd) = at_and_ucmd!();