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", &timestamps, 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, &timestamps) {
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