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