• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]
test_y2038_with_utimensat()9 fn 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", &timestamps, 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]
test_y2038_with_futimens()108 fn 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, &timestamps) {
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