1b8a62b91Sopenharmony_ci/// Test that we can set a file timestamp to a date past the year 2038 with 2b8a62b91Sopenharmony_ci/// `utimensat` and read it back again. 3b8a62b91Sopenharmony_ci/// 4b8a62b91Sopenharmony_ci/// See tests/time/y2038.rs for more information about y2038 testing. 5b8a62b91Sopenharmony_ci#[cfg(not(all(target_env = "musl", target_pointer_width = "32")))] 6b8a62b91Sopenharmony_ci#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] 7b8a62b91Sopenharmony_ci#[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))] 8b8a62b91Sopenharmony_ci#[test] 9b8a62b91Sopenharmony_cifn test_y2038_with_utimensat() { 10b8a62b91Sopenharmony_ci use rustix::fs::{ 11b8a62b91Sopenharmony_ci cwd, fstat, openat, statat, utimensat, AtFlags, Mode, OFlags, Timespec, Timestamps, 12b8a62b91Sopenharmony_ci }; 13b8a62b91Sopenharmony_ci use std::convert::TryInto; 14b8a62b91Sopenharmony_ci 15b8a62b91Sopenharmony_ci let tmp = tempfile::tempdir().unwrap(); 16b8a62b91Sopenharmony_ci let dir = openat(&cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); 17b8a62b91Sopenharmony_ci 18b8a62b91Sopenharmony_ci let m_sec = 1_u64 << 32; 19b8a62b91Sopenharmony_ci let m_nsec = 17_u32; 20b8a62b91Sopenharmony_ci let a_sec = m_sec + 1; 21b8a62b91Sopenharmony_ci let a_nsec = m_nsec + 1; 22b8a62b91Sopenharmony_ci 23b8a62b91Sopenharmony_ci let timestamps = Timestamps { 24b8a62b91Sopenharmony_ci last_modification: Timespec { 25b8a62b91Sopenharmony_ci tv_sec: m_sec as _, 26b8a62b91Sopenharmony_ci tv_nsec: m_nsec as _, 27b8a62b91Sopenharmony_ci }, 28b8a62b91Sopenharmony_ci last_access: Timespec { 29b8a62b91Sopenharmony_ci tv_sec: a_sec as _, 30b8a62b91Sopenharmony_ci tv_nsec: a_nsec as _, 31b8a62b91Sopenharmony_ci }, 32b8a62b91Sopenharmony_ci }; 33b8a62b91Sopenharmony_ci let _ = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::RUSR).unwrap(); 34b8a62b91Sopenharmony_ci 35b8a62b91Sopenharmony_ci match utimensat(&dir, "foo", ×tamps, AtFlags::empty()) { 36b8a62b91Sopenharmony_ci Ok(()) => (), 37b8a62b91Sopenharmony_ci 38b8a62b91Sopenharmony_ci // On 32-bit platforms, accept `EOVERFLOW`, meaning that y2038 support 39b8a62b91Sopenharmony_ci // is not available in this version of the OS. 40b8a62b91Sopenharmony_ci #[cfg(target_pointer_width = "32")] 41b8a62b91Sopenharmony_ci Err(rustix::io::Errno::OVERFLOW) => return, 42b8a62b91Sopenharmony_ci 43b8a62b91Sopenharmony_ci Err(err) => panic!("unexpected error: {:?}", err), 44b8a62b91Sopenharmony_ci } 45b8a62b91Sopenharmony_ci 46b8a62b91Sopenharmony_ci // Use `statat` to read back the timestamp. 47b8a62b91Sopenharmony_ci let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); 48b8a62b91Sopenharmony_ci 49b8a62b91Sopenharmony_ci assert_eq!( 50b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_mtime).unwrap() as u64, 51b8a62b91Sopenharmony_ci m_sec 52b8a62b91Sopenharmony_ci ); 53b8a62b91Sopenharmony_ci 54b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 55b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtime_nsec as u32, m_nsec); 56b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 57b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtimensec as u32, m_nsec); 58b8a62b91Sopenharmony_ci 59b8a62b91Sopenharmony_ci assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 >= a_sec); 60b8a62b91Sopenharmony_ci 61b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 62b8a62b91Sopenharmony_ci assert!( 63b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec 64b8a62b91Sopenharmony_ci || stat.st_atime_nsec as u32 >= a_nsec 65b8a62b91Sopenharmony_ci ); 66b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 67b8a62b91Sopenharmony_ci assert!( 68b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec 69b8a62b91Sopenharmony_ci || stat.st_atimensec as u32 >= a_nsec 70b8a62b91Sopenharmony_ci ); 71b8a62b91Sopenharmony_ci 72b8a62b91Sopenharmony_ci // Now test the same thing, but with `fstat`. 73b8a62b91Sopenharmony_ci let file = openat(&dir, "foo", OFlags::RDONLY, Mode::empty()).unwrap(); 74b8a62b91Sopenharmony_ci let stat = fstat(&file).unwrap(); 75b8a62b91Sopenharmony_ci 76b8a62b91Sopenharmony_ci assert_eq!( 77b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_mtime).unwrap() as u64, 78b8a62b91Sopenharmony_ci m_sec 79b8a62b91Sopenharmony_ci ); 80b8a62b91Sopenharmony_ci 81b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 82b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtime_nsec as u32, m_nsec); 83b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 84b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtimensec as u32, m_nsec); 85b8a62b91Sopenharmony_ci 86b8a62b91Sopenharmony_ci assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 >= a_sec); 87b8a62b91Sopenharmony_ci 88b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 89b8a62b91Sopenharmony_ci assert!( 90b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec 91b8a62b91Sopenharmony_ci || stat.st_atime_nsec as u32 >= a_nsec 92b8a62b91Sopenharmony_ci ); 93b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 94b8a62b91Sopenharmony_ci assert!( 95b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec 96b8a62b91Sopenharmony_ci || stat.st_atimensec as u32 >= a_nsec 97b8a62b91Sopenharmony_ci ); 98b8a62b91Sopenharmony_ci} 99b8a62b91Sopenharmony_ci 100b8a62b91Sopenharmony_ci/// Test that we can set a file timestamp to a date past the year 2038 with 101b8a62b91Sopenharmony_ci/// `futimens` and read it back again. 102b8a62b91Sopenharmony_ci/// 103b8a62b91Sopenharmony_ci/// See tests/time/y2038.rs for more information about y2038 testing. 104b8a62b91Sopenharmony_ci#[cfg(not(all(target_env = "musl", target_pointer_width = "32")))] 105b8a62b91Sopenharmony_ci#[cfg(not(all(target_os = "android", target_pointer_width = "32")))] 106b8a62b91Sopenharmony_ci#[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))] 107b8a62b91Sopenharmony_ci#[test] 108b8a62b91Sopenharmony_cifn test_y2038_with_futimens() { 109b8a62b91Sopenharmony_ci use rustix::fs::{ 110b8a62b91Sopenharmony_ci cwd, fstat, futimens, openat, statat, AtFlags, Mode, OFlags, Timespec, Timestamps, 111b8a62b91Sopenharmony_ci }; 112b8a62b91Sopenharmony_ci use std::convert::TryInto; 113b8a62b91Sopenharmony_ci 114b8a62b91Sopenharmony_ci let tmp = tempfile::tempdir().unwrap(); 115b8a62b91Sopenharmony_ci let dir = openat(&cwd(), tmp.path(), OFlags::RDONLY, Mode::empty()).unwrap(); 116b8a62b91Sopenharmony_ci 117b8a62b91Sopenharmony_ci let m_sec = 1_u64 << 32; 118b8a62b91Sopenharmony_ci let m_nsec = 17_u32; 119b8a62b91Sopenharmony_ci let a_sec = m_sec + 1; 120b8a62b91Sopenharmony_ci let a_nsec = m_nsec + 1; 121b8a62b91Sopenharmony_ci 122b8a62b91Sopenharmony_ci let timestamps = Timestamps { 123b8a62b91Sopenharmony_ci last_modification: Timespec { 124b8a62b91Sopenharmony_ci tv_sec: m_sec as _, 125b8a62b91Sopenharmony_ci tv_nsec: m_nsec as _, 126b8a62b91Sopenharmony_ci }, 127b8a62b91Sopenharmony_ci last_access: Timespec { 128b8a62b91Sopenharmony_ci tv_sec: a_sec as _, 129b8a62b91Sopenharmony_ci tv_nsec: a_nsec as _, 130b8a62b91Sopenharmony_ci }, 131b8a62b91Sopenharmony_ci }; 132b8a62b91Sopenharmony_ci let file = openat(&dir, "foo", OFlags::CREATE | OFlags::WRONLY, Mode::RUSR).unwrap(); 133b8a62b91Sopenharmony_ci 134b8a62b91Sopenharmony_ci match futimens(&file, ×tamps) { 135b8a62b91Sopenharmony_ci Ok(()) => (), 136b8a62b91Sopenharmony_ci 137b8a62b91Sopenharmony_ci // On 32-bit platforms, accept `EOVERFLOW`, meaning that y2038 support 138b8a62b91Sopenharmony_ci // is not available in this version of the OS. 139b8a62b91Sopenharmony_ci #[cfg(target_pointer_width = "32")] 140b8a62b91Sopenharmony_ci Err(rustix::io::Errno::OVERFLOW) => return, 141b8a62b91Sopenharmony_ci 142b8a62b91Sopenharmony_ci Err(err) => panic!("unexpected error: {:?}", err), 143b8a62b91Sopenharmony_ci } 144b8a62b91Sopenharmony_ci 145b8a62b91Sopenharmony_ci // Use `statat` to read back the timestamp. 146b8a62b91Sopenharmony_ci let stat = statat(&dir, "foo", AtFlags::empty()).unwrap(); 147b8a62b91Sopenharmony_ci 148b8a62b91Sopenharmony_ci assert_eq!(TryInto::<u64>::try_into(stat.st_mtime).unwrap(), m_sec); 149b8a62b91Sopenharmony_ci 150b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 151b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtime_nsec as u32, m_nsec); 152b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 153b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtimensec as u32, m_nsec); 154b8a62b91Sopenharmony_ci 155b8a62b91Sopenharmony_ci assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() >= a_sec); 156b8a62b91Sopenharmony_ci 157b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 158b8a62b91Sopenharmony_ci assert!( 159b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() > a_sec 160b8a62b91Sopenharmony_ci || stat.st_atime_nsec as u32 >= a_nsec 161b8a62b91Sopenharmony_ci ); 162b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 163b8a62b91Sopenharmony_ci assert!( 164b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() > a_sec 165b8a62b91Sopenharmony_ci || stat.st_atimensec as u32 >= a_nsec 166b8a62b91Sopenharmony_ci ); 167b8a62b91Sopenharmony_ci 168b8a62b91Sopenharmony_ci // Now test the same thing, but with `fstat`. 169b8a62b91Sopenharmony_ci let file = openat(&dir, "foo", OFlags::RDONLY, Mode::empty()).unwrap(); 170b8a62b91Sopenharmony_ci let stat = fstat(&file).unwrap(); 171b8a62b91Sopenharmony_ci 172b8a62b91Sopenharmony_ci assert_eq!( 173b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_mtime).unwrap() as u64, 174b8a62b91Sopenharmony_ci m_sec 175b8a62b91Sopenharmony_ci ); 176b8a62b91Sopenharmony_ci 177b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 178b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtime_nsec as u32, m_nsec); 179b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 180b8a62b91Sopenharmony_ci assert_eq!(stat.st_mtimensec as u32, m_nsec); 181b8a62b91Sopenharmony_ci 182b8a62b91Sopenharmony_ci assert!(TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 >= a_sec); 183b8a62b91Sopenharmony_ci 184b8a62b91Sopenharmony_ci #[cfg(not(target_os = "netbsd"))] 185b8a62b91Sopenharmony_ci assert!( 186b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec 187b8a62b91Sopenharmony_ci || stat.st_atime_nsec as u32 >= a_nsec 188b8a62b91Sopenharmony_ci ); 189b8a62b91Sopenharmony_ci #[cfg(target_os = "netbsd")] 190b8a62b91Sopenharmony_ci assert!( 191b8a62b91Sopenharmony_ci TryInto::<u64>::try_into(stat.st_atime).unwrap() as u64 > a_sec 192b8a62b91Sopenharmony_ci || stat.st_atimensec as u32 >= a_nsec 193b8a62b91Sopenharmony_ci ); 194b8a62b91Sopenharmony_ci} 195