From 7daeccb0a98005f02dd644f2d0197e4602313547 Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Sat, 15 Mar 2025 09:42:13 +0100 Subject: [PATCH 1/4] Test main for failure seen in #7378 for Y2038 bug It's unclear to me how the failure seen in #7378 is related to the change in the PR, it just happen that the test need to try touching in 2068. The 2^32 error in the test makes me strongly think of the year 2038 bug, so I added a test for that. --- tests/by-util/test_touch.rs | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 746d2170412..259a39c31fa 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -4,9 +4,10 @@ // file that was distributed with this source code. // spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms datetime mktime -use filetime::FileTime; +use chrono::NaiveDate; #[cfg(not(target_os = "freebsd"))] use filetime::set_symlink_file_times; +use filetime::FileTime; use std::fs::remove_file; use std::path::PathBuf; use uutests::at_and_ucmd; @@ -184,6 +185,47 @@ fn test_touch_2_digit_years_69() { assert_eq!(mtime, expected); } +#[test] +fn test_y2038_touch() { + // Jan 19 2038, 03:14:07 UTC is the moment of the Y2038 bug + // test 1 second before, at, and 1 second after + let year = 2038; + let month = 1; + let day = 19; + let hours = 3; + let minutes = 14; + let seconds = 7; + for deltas in [-1i32, 0, 1] { + let (at, mut ucmd) = at_and_ucmd!(); + + let date = NaiveDate::from_ymd_opt(year, month, day).unwrap(); + let datetime = date + .and_hms_opt(hours, minutes, (seconds + deltas).try_into().unwrap()) + .unwrap(); + let timestamp = datetime.and_utc().timestamp(); + + let date = format!( + "{}{:02}{:02}{:02}{:02}.{:02}", + year, + month, + day, + hours, + minutes, + seconds + deltas + ); + let file = format!("Y2038_{}_{}", date, deltas); + ucmd.args(&["-t", &date, &file]).succeeds().no_output(); + + assert!(at.file_exists(&file)); + + let expected = FileTime::from_unix_time(timestamp, 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_ymdhm_time() { let (at, mut ucmd) = at_and_ucmd!(); From 11d202e9b90531d6b9cf44a20d92439dec1426e2 Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Mon, 28 Apr 2025 16:20:47 +0200 Subject: [PATCH 2/4] expand tests --- tests/by-util/test_touch.rs | 89 ++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 259a39c31fa..982300fbed4 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -4,7 +4,6 @@ // file that was distributed with this source code. // spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms datetime mktime -use chrono::NaiveDate; #[cfg(not(target_os = "freebsd"))] use filetime::set_symlink_file_times; use filetime::FileTime; @@ -186,44 +185,60 @@ fn test_touch_2_digit_years_69() { } #[test] -fn test_y2038_touch() { +fn test_y2038_touch_last_before() { // Jan 19 2038, 03:14:07 UTC is the moment of the Y2038 bug - // test 1 second before, at, and 1 second after - let year = 2038; - let month = 1; - let day = 19; - let hours = 3; - let minutes = 14; - let seconds = 7; - for deltas in [-1i32, 0, 1] { - let (at, mut ucmd) = at_and_ucmd!(); + let (at, mut ucmd) = at_and_ucmd!(); - let date = NaiveDate::from_ymd_opt(year, month, day).unwrap(); - let datetime = date - .and_hms_opt(hours, minutes, (seconds + deltas).try_into().unwrap()) - .unwrap(); - let timestamp = datetime.and_utc().timestamp(); - - let date = format!( - "{}{:02}{:02}{:02}{:02}.{:02}", - year, - month, - day, - hours, - minutes, - seconds + deltas - ); - let file = format!("Y2038_{}_{}", date, deltas); - ucmd.args(&["-t", &date, &file]).succeeds().no_output(); - - assert!(at.file_exists(&file)); - - let expected = FileTime::from_unix_time(timestamp, 0); - let (atime, mtime) = get_file_times(&at, &file); - assert_eq!(atime, mtime); - assert_eq!(atime, expected); - assert_eq!(mtime, expected); - } + let f1 = "Y2038_203801190314.07"; + ucmd.args(&["-t", "203801190314.07", f1]) + .succeeds() + .no_output(); + + assert!(at.file_exists(f1)); + // + let expected = FileTime::from_unix_time(2i64.pow(31) - 1, 0); + let (atime, mtime) = get_file_times(&at, f1); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + +#[test] +fn test_y2038_touch_at() { + // Jan 19 2038, 03:14:07 UTC is the moment of the Y2038 bug + let (at, mut ucmd) = at_and_ucmd!(); + + let f1 = "Y2038_203801190314.08"; + ucmd.args(&["-t", "203801190314.08", f1]) + .succeeds() + .no_output(); + + assert!(at.file_exists(f1)); + // + let expected = FileTime::from_unix_time(2i64.pow(31), 0); + let (atime, mtime) = get_file_times(&at, f1); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + +#[test] +fn test_y2038_touch_just_after() { + // Jan 19 2038, 03:14:07 UTC is the moment of the Y2038 bug + let (at, mut ucmd) = at_and_ucmd!(); + + let f1 = "Y2038_203801190314.09"; + ucmd.args(&["-t", "203801190314.09", f1]) + .succeeds() + .no_output(); + + assert!(at.file_exists(f1)); + // + let expected = FileTime::from_unix_time(2i64.pow(31) + 1, 0); + let (atime, mtime) = get_file_times(&at, f1); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); } #[test] From 35c9aff3d6067424b925d6421a94dc1f8239b328 Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Sat, 3 May 2025 12:00:04 +0200 Subject: [PATCH 3/4] cargo reformat --- tests/by-util/test_touch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 982300fbed4..ee4c73a1efe 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -4,9 +4,9 @@ // file that was distributed with this source code. // spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms datetime mktime +use filetime::FileTime; #[cfg(not(target_os = "freebsd"))] use filetime::set_symlink_file_times; -use filetime::FileTime; use std::fs::remove_file; use std::path::PathBuf; use uutests::at_and_ucmd; From cff632c7ff35bb0c684ee0e517d4a24d17dd642f Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Sat, 3 May 2025 12:07:24 +0200 Subject: [PATCH 4/4] test only on 64 bits --- tests/by-util/test_touch.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index ee4c73a1efe..b38b9ad4a5b 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -204,6 +204,7 @@ fn test_y2038_touch_last_before() { } #[test] +#[cfg(target_pointer_width = "64")] fn test_y2038_touch_at() { // Jan 19 2038, 03:14:07 UTC is the moment of the Y2038 bug let (at, mut ucmd) = at_and_ucmd!(); @@ -223,6 +224,7 @@ fn test_y2038_touch_at() { } #[test] +#[cfg(target_pointer_width = "64")] fn test_y2038_touch_just_after() { // Jan 19 2038, 03:14:07 UTC is the moment of the Y2038 bug let (at, mut ucmd) = at_and_ucmd!();