]>
Commit | Line | Data |
---|---|---|
476ff2be SL |
1 | //! Timestamps for files in Rust |
2 | //! | |
3 | //! This library provides platform-agnostic inspection of the various timestamps | |
4 | //! present in the standard `fs::Metadata` structure. | |
5 | //! | |
6 | //! # Installation | |
7 | //! | |
ea8adc8c | 8 | //! Add this to your `Cargo.toml`: |
476ff2be SL |
9 | //! |
10 | //! ```toml | |
11 | //! [dependencies] | |
74b04a01 | 12 | //! filetime = "0.2" |
476ff2be SL |
13 | //! ``` |
14 | //! | |
15 | //! # Usage | |
16 | //! | |
17 | //! ```no_run | |
18 | //! use std::fs; | |
19 | //! use filetime::FileTime; | |
20 | //! | |
21 | //! let metadata = fs::metadata("foo.txt").unwrap(); | |
22 | //! | |
23 | //! let mtime = FileTime::from_last_modification_time(&metadata); | |
24 | //! println!("{}", mtime); | |
25 | //! | |
26 | //! let atime = FileTime::from_last_access_time(&metadata); | |
27 | //! assert!(mtime < atime); | |
28 | //! | |
29 | //! // Inspect values that can be interpreted across platforms | |
83c7162d | 30 | //! println!("{}", mtime.unix_seconds()); |
476ff2be SL |
31 | //! println!("{}", mtime.nanoseconds()); |
32 | //! | |
33 | //! // Print the platform-specific value of seconds | |
34 | //! println!("{}", mtime.seconds()); | |
35 | //! ``` | |
36 | ||
476ff2be SL |
37 | use std::fmt; |
38 | use std::fs; | |
39 | use std::io; | |
40 | use std::path::Path; | |
83c7162d | 41 | use std::time::{Duration, SystemTime, UNIX_EPOCH}; |
476ff2be | 42 | |
74b04a01 | 43 | cfg_if::cfg_if! { |
abe05a73 XL |
44 | if #[cfg(target_os = "redox")] { |
45 | #[path = "redox.rs"] | |
46 | mod imp; | |
47 | } else if #[cfg(windows)] { | |
48 | #[path = "windows.rs"] | |
49 | mod imp; | |
74b04a01 XL |
50 | } else if #[cfg(target_arch = "wasm32")] { |
51 | #[path = "wasm.rs"] | |
52 | mod imp; | |
abe05a73 XL |
53 | } else { |
54 | #[path = "unix/mod.rs"] | |
55 | mod imp; | |
56 | } | |
57 | } | |
ea8adc8c | 58 | |
476ff2be SL |
59 | /// A helper structure to represent a timestamp for a file. |
60 | /// | |
61 | /// The actual value contined within is platform-specific and does not have the | |
62 | /// same meaning across platforms, but comparisons and stringification can be | |
63 | /// significant among the same platform. | |
64 | #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone, Hash)] | |
65 | pub struct FileTime { | |
83c7162d | 66 | seconds: i64, |
476ff2be SL |
67 | nanos: u32, |
68 | } | |
69 | ||
70 | impl FileTime { | |
71 | /// Creates a new timestamp representing a 0 time. | |
72 | /// | |
73 | /// Useful for creating the base of a cmp::max chain of times. | |
74 | pub fn zero() -> FileTime { | |
74b04a01 XL |
75 | FileTime { |
76 | seconds: 0, | |
77 | nanos: 0, | |
78 | } | |
79 | } | |
80 | ||
81 | fn emulate_second_only_system(self) -> FileTime { | |
82 | if cfg!(emulate_second_only_system) { | |
83 | FileTime { | |
84 | seconds: self.seconds, | |
85 | nanos: 0, | |
86 | } | |
87 | } else { | |
88 | self | |
89 | } | |
476ff2be SL |
90 | } |
91 | ||
ba9703b0 XL |
92 | /// Creates a new timestamp representing the current system time. |
93 | /// | |
94 | /// ``` | |
95 | /// # use filetime::FileTime; | |
96 | /// # | |
97 | /// # fn example() -> std::io::Result<()> { | |
98 | /// # let path = ""; | |
99 | /// # | |
100 | /// filetime::set_file_mtime(path, FileTime::now())?; | |
101 | /// # | |
102 | /// # Ok(()) | |
103 | /// # } | |
104 | /// ``` | |
105 | /// | |
106 | /// Equivalent to `FileTime::from_system_time(SystemTime::now())`. | |
107 | pub fn now() -> FileTime { | |
108 | FileTime::from_system_time(SystemTime::now()) | |
109 | } | |
110 | ||
476ff2be | 111 | /// Creates a new instance of `FileTime` with a number of seconds and |
83c7162d XL |
112 | /// nanoseconds relative to the Unix epoch, 1970-01-01T00:00:00Z. |
113 | /// | |
114 | /// Negative seconds represent times before the Unix epoch, and positive | |
115 | /// values represent times after it. Nanos always count forwards in time. | |
476ff2be SL |
116 | /// |
117 | /// Note that this is typically the relative point that Unix time stamps are | |
118 | /// from, but on Windows the native time stamp is relative to January 1, | |
119 | /// 1601 so the return value of `seconds` from the returned `FileTime` | |
120 | /// instance may not be the same as that passed in. | |
83c7162d | 121 | pub fn from_unix_time(seconds: i64, nanos: u32) -> FileTime { |
476ff2be | 122 | FileTime { |
74b04a01 | 123 | seconds: seconds + if cfg!(windows) { 11644473600 } else { 0 }, |
83c7162d | 124 | nanos, |
476ff2be | 125 | } |
74b04a01 | 126 | .emulate_second_only_system() |
476ff2be SL |
127 | } |
128 | ||
129 | /// Creates a new timestamp from the last modification time listed in the | |
130 | /// specified metadata. | |
131 | /// | |
132 | /// The returned value corresponds to the `mtime` field of `stat` on Unix | |
133 | /// platforms and the `ftLastWriteTime` field on Windows platforms. | |
134 | pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { | |
74b04a01 | 135 | imp::from_last_modification_time(meta).emulate_second_only_system() |
476ff2be SL |
136 | } |
137 | ||
138 | /// Creates a new timestamp from the last access time listed in the | |
139 | /// specified metadata. | |
140 | /// | |
141 | /// The returned value corresponds to the `atime` field of `stat` on Unix | |
142 | /// platforms and the `ftLastAccessTime` field on Windows platforms. | |
143 | pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { | |
74b04a01 | 144 | imp::from_last_access_time(meta).emulate_second_only_system() |
476ff2be SL |
145 | } |
146 | ||
147 | /// Creates a new timestamp from the creation time listed in the specified | |
148 | /// metadata. | |
149 | /// | |
150 | /// The returned value corresponds to the `birthtime` field of `stat` on | |
151 | /// Unix platforms and the `ftCreationTime` field on Windows platforms. Note | |
152 | /// that not all Unix platforms have this field available and may return | |
153 | /// `None` in some circumstances. | |
154 | pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> { | |
74b04a01 | 155 | imp::from_creation_time(meta).map(|x| x.emulate_second_only_system()) |
476ff2be SL |
156 | } |
157 | ||
83c7162d XL |
158 | /// Creates a new timestamp from the given SystemTime. |
159 | /// | |
160 | /// Windows counts file times since 1601-01-01T00:00:00Z, and cannot | |
161 | /// represent times before this, but it's possible to create a SystemTime | |
162 | /// that does. This function will error if passed such a SystemTime. | |
163 | pub fn from_system_time(time: SystemTime) -> FileTime { | |
164 | let epoch = if cfg!(windows) { | |
165 | UNIX_EPOCH - Duration::from_secs(11644473600) | |
166 | } else { | |
167 | UNIX_EPOCH | |
168 | }; | |
169 | ||
74b04a01 XL |
170 | time.duration_since(epoch) |
171 | .map(|d| FileTime { | |
172 | seconds: d.as_secs() as i64, | |
173 | nanos: d.subsec_nanos(), | |
174 | }) | |
175 | .unwrap_or_else(|e| { | |
176 | let until_epoch = e.duration(); | |
177 | let (sec_offset, nanos) = if until_epoch.subsec_nanos() == 0 { | |
178 | (0, 0) | |
179 | } else { | |
180 | (-1, 1_000_000_000 - until_epoch.subsec_nanos()) | |
181 | }; | |
182 | ||
183 | FileTime { | |
184 | seconds: -1 * until_epoch.as_secs() as i64 + sec_offset, | |
185 | nanos, | |
186 | } | |
187 | }) | |
188 | .emulate_second_only_system() | |
83c7162d XL |
189 | } |
190 | ||
476ff2be SL |
191 | /// Returns the whole number of seconds represented by this timestamp. |
192 | /// | |
193 | /// Note that this value's meaning is **platform specific**. On Unix | |
194 | /// platform time stamps are typically relative to January 1, 1970, but on | |
195 | /// Windows platforms time stamps are relative to January 1, 1601. | |
74b04a01 XL |
196 | pub fn seconds(&self) -> i64 { |
197 | self.seconds | |
198 | } | |
476ff2be SL |
199 | |
200 | /// Returns the whole number of seconds represented by this timestamp, | |
201 | /// relative to the Unix epoch start of January 1, 1970. | |
202 | /// | |
203 | /// Note that this does not return the same value as `seconds` for Windows | |
204 | /// platforms as seconds are relative to a different date there. | |
83c7162d | 205 | pub fn unix_seconds(&self) -> i64 { |
74b04a01 | 206 | self.seconds - if cfg!(windows) { 11644473600 } else { 0 } |
476ff2be SL |
207 | } |
208 | ||
209 | /// Returns the nanosecond precision of this timestamp. | |
210 | /// | |
211 | /// The returned value is always less than one billion and represents a | |
212 | /// portion of a second forward from the seconds returned by the `seconds` | |
213 | /// method. | |
74b04a01 XL |
214 | pub fn nanoseconds(&self) -> u32 { |
215 | self.nanos | |
216 | } | |
476ff2be SL |
217 | } |
218 | ||
219 | impl fmt::Display for FileTime { | |
220 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
221 | write!(f, "{}.{:09}s", self.seconds, self.nanos) | |
222 | } | |
223 | } | |
224 | ||
0731742a XL |
225 | impl From<SystemTime> for FileTime { |
226 | fn from(time: SystemTime) -> FileTime { | |
227 | FileTime::from_system_time(time) | |
228 | } | |
229 | } | |
230 | ||
476ff2be SL |
231 | /// Set the last access and modification times for a file on the filesystem. |
232 | /// | |
233 | /// This function will set the `atime` and `mtime` metadata fields for a file | |
234 | /// on the local filesystem, returning any error encountered. | |
74b04a01 XL |
235 | pub fn set_file_times<P>(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> |
236 | where | |
237 | P: AsRef<Path>, | |
ea8adc8c XL |
238 | { |
239 | imp::set_file_times(p.as_ref(), atime, mtime) | |
476ff2be SL |
240 | } |
241 | ||
74b04a01 XL |
242 | /// Set the last access and modification times for a file handle. |
243 | /// | |
244 | /// This function will either or both of the `atime` and `mtime` metadata | |
245 | /// fields for a file handle , returning any error encountered. If `None` is | |
246 | /// specified then the time won't be updated. If `None` is specified for both | |
247 | /// options then no action is taken. | |
248 | pub fn set_file_handle_times( | |
249 | f: &fs::File, | |
250 | atime: Option<FileTime>, | |
251 | mtime: Option<FileTime>, | |
252 | ) -> io::Result<()> { | |
253 | imp::set_file_handle_times(f, atime, mtime) | |
254 | } | |
255 | ||
ea8adc8c XL |
256 | /// Set the last access and modification times for a file on the filesystem. |
257 | /// This function does not follow symlink. | |
258 | /// | |
259 | /// This function will set the `atime` and `mtime` metadata fields for a file | |
260 | /// on the local filesystem, returning any error encountered. | |
74b04a01 XL |
261 | pub fn set_symlink_file_times<P>(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> |
262 | where | |
263 | P: AsRef<Path>, | |
ea8adc8c XL |
264 | { |
265 | imp::set_symlink_file_times(p.as_ref(), atime, mtime) | |
476ff2be SL |
266 | } |
267 | ||
74b04a01 XL |
268 | /// Set the last modification time for a file on the filesystem. |
269 | /// | |
270 | /// This function will set the `mtime` metadata field for a file on the local | |
271 | /// filesystem, returning any error encountered. | |
272 | /// | |
273 | /// # Platform support | |
274 | /// | |
275 | /// Where supported this will attempt to issue just one syscall to update only | |
276 | /// the `mtime`, but where not supported this may issue one syscall to learn the | |
277 | /// existing `atime` so only the `mtime` can be configured. | |
278 | pub fn set_file_mtime<P>(p: P, mtime: FileTime) -> io::Result<()> | |
279 | where | |
280 | P: AsRef<Path>, | |
281 | { | |
282 | imp::set_file_mtime(p.as_ref(), mtime) | |
283 | } | |
284 | ||
285 | /// Set the last access time for a file on the filesystem. | |
286 | /// | |
287 | /// This function will set the `atime` metadata field for a file on the local | |
288 | /// filesystem, returning any error encountered. | |
289 | /// | |
290 | /// # Platform support | |
291 | /// | |
292 | /// Where supported this will attempt to issue just one syscall to update only | |
293 | /// the `atime`, but where not supported this may issue one syscall to learn the | |
294 | /// existing `mtime` so only the `atime` can be configured. | |
295 | pub fn set_file_atime<P>(p: P, atime: FileTime) -> io::Result<()> | |
296 | where | |
297 | P: AsRef<Path>, | |
298 | { | |
299 | imp::set_file_atime(p.as_ref(), atime) | |
300 | } | |
301 | ||
476ff2be SL |
302 | #[cfg(test)] |
303 | mod tests { | |
74b04a01 XL |
304 | use super::{set_file_handle_times, set_file_times, set_symlink_file_times, FileTime}; |
305 | use std::fs::{self, File}; | |
ea8adc8c XL |
306 | use std::io; |
307 | use std::path::Path; | |
83c7162d | 308 | use std::time::{Duration, UNIX_EPOCH}; |
74b04a01 | 309 | use tempfile::Builder; |
ea8adc8c XL |
310 | |
311 | #[cfg(unix)] | |
74b04a01 XL |
312 | fn make_symlink<P, Q>(src: P, dst: Q) -> io::Result<()> |
313 | where | |
314 | P: AsRef<Path>, | |
315 | Q: AsRef<Path>, | |
ea8adc8c XL |
316 | { |
317 | use std::os::unix::fs::symlink; | |
318 | symlink(src, dst) | |
319 | } | |
320 | ||
321 | #[cfg(windows)] | |
74b04a01 XL |
322 | fn make_symlink<P, Q>(src: P, dst: Q) -> io::Result<()> |
323 | where | |
324 | P: AsRef<Path>, | |
325 | Q: AsRef<Path>, | |
ea8adc8c XL |
326 | { |
327 | use std::os::windows::fs::symlink_file; | |
328 | symlink_file(src, dst) | |
329 | } | |
476ff2be | 330 | |
83c7162d XL |
331 | #[test] |
332 | #[cfg(windows)] | |
333 | fn from_unix_time_test() { | |
334 | let time = FileTime::from_unix_time(10, 100_000_000); | |
335 | assert_eq!(11644473610, time.seconds); | |
336 | assert_eq!(100_000_000, time.nanos); | |
337 | ||
338 | let time = FileTime::from_unix_time(-10, 100_000_000); | |
339 | assert_eq!(11644473590, time.seconds); | |
340 | assert_eq!(100_000_000, time.nanos); | |
341 | ||
342 | let time = FileTime::from_unix_time(-12_000_000_000, 0); | |
343 | assert_eq!(-355526400, time.seconds); | |
344 | assert_eq!(0, time.nanos); | |
345 | } | |
346 | ||
347 | #[test] | |
348 | #[cfg(not(windows))] | |
349 | fn from_unix_time_test() { | |
350 | let time = FileTime::from_unix_time(10, 100_000_000); | |
351 | assert_eq!(10, time.seconds); | |
352 | assert_eq!(100_000_000, time.nanos); | |
353 | ||
354 | let time = FileTime::from_unix_time(-10, 100_000_000); | |
355 | assert_eq!(-10, time.seconds); | |
356 | assert_eq!(100_000_000, time.nanos); | |
357 | ||
358 | let time = FileTime::from_unix_time(-12_000_000_000, 0); | |
359 | assert_eq!(-12_000_000_000, time.seconds); | |
360 | assert_eq!(0, time.nanos); | |
361 | } | |
362 | ||
363 | #[test] | |
364 | #[cfg(windows)] | |
365 | fn from_system_time_test() { | |
366 | let time = FileTime::from_system_time(UNIX_EPOCH + Duration::from_secs(10)); | |
367 | assert_eq!(11644473610, time.seconds); | |
368 | assert_eq!(0, time.nanos); | |
369 | ||
370 | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(10)); | |
371 | assert_eq!(11644473590, time.seconds); | |
372 | assert_eq!(0, time.nanos); | |
373 | ||
374 | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_millis(1100)); | |
375 | assert_eq!(11644473598, time.seconds); | |
376 | assert_eq!(900_000_000, time.nanos); | |
377 | ||
378 | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(12_000_000_000)); | |
379 | assert_eq!(-355526400, time.seconds); | |
380 | assert_eq!(0, time.nanos); | |
381 | } | |
382 | ||
383 | #[test] | |
384 | #[cfg(not(windows))] | |
385 | fn from_system_time_test() { | |
386 | let time = FileTime::from_system_time(UNIX_EPOCH + Duration::from_secs(10)); | |
387 | assert_eq!(10, time.seconds); | |
388 | assert_eq!(0, time.nanos); | |
389 | ||
390 | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(10)); | |
391 | assert_eq!(-10, time.seconds); | |
392 | assert_eq!(0, time.nanos); | |
393 | ||
394 | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_millis(1100)); | |
395 | assert_eq!(-2, time.seconds); | |
396 | assert_eq!(900_000_000, time.nanos); | |
397 | ||
8faf50e0 XL |
398 | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(12_000_000)); |
399 | assert_eq!(-12_000_000, time.seconds); | |
83c7162d XL |
400 | assert_eq!(0, time.nanos); |
401 | } | |
402 | ||
476ff2be | 403 | #[test] |
74b04a01 XL |
404 | fn set_file_times_test() -> io::Result<()> { |
405 | let td = Builder::new().prefix("filetime").tempdir()?; | |
476ff2be | 406 | let path = td.path().join("foo.txt"); |
74b04a01 | 407 | let mut f = File::create(&path)?; |
476ff2be | 408 | |
74b04a01 | 409 | let metadata = fs::metadata(&path)?; |
476ff2be SL |
410 | let mtime = FileTime::from_last_modification_time(&metadata); |
411 | let atime = FileTime::from_last_access_time(&metadata); | |
74b04a01 | 412 | set_file_times(&path, atime, mtime)?; |
476ff2be | 413 | |
83c7162d | 414 | let new_mtime = FileTime::from_unix_time(10_000, 0); |
74b04a01 | 415 | set_file_times(&path, atime, new_mtime)?; |
476ff2be | 416 | |
74b04a01 | 417 | let metadata = fs::metadata(&path)?; |
476ff2be | 418 | let mtime = FileTime::from_last_modification_time(&metadata); |
74b04a01 XL |
419 | assert_eq!(mtime, new_mtime, "modification should be updated"); |
420 | ||
421 | // Update just mtime | |
422 | let new_mtime = FileTime::from_unix_time(20_000, 0); | |
423 | set_file_handle_times(&mut f, None, Some(new_mtime))?; | |
424 | let metadata = f.metadata()?; | |
425 | let mtime = FileTime::from_last_modification_time(&metadata); | |
426 | assert_eq!(mtime, new_mtime, "modification time should be updated"); | |
427 | let new_atime = FileTime::from_last_access_time(&metadata); | |
428 | assert_eq!(atime, new_atime, "accessed time should not be updated"); | |
429 | ||
430 | // Update just atime | |
431 | let new_atime = FileTime::from_unix_time(30_000, 0); | |
432 | set_file_handle_times(&mut f, Some(new_atime), None)?; | |
433 | let metadata = f.metadata()?; | |
434 | let mtime = FileTime::from_last_modification_time(&metadata); | |
435 | assert_eq!(mtime, new_mtime, "modification time should not be updated"); | |
436 | let atime = FileTime::from_last_access_time(&metadata); | |
437 | assert_eq!(atime, new_atime, "accessed time should be updated"); | |
ea8adc8c XL |
438 | |
439 | let spath = td.path().join("bar.txt"); | |
74b04a01 XL |
440 | make_symlink(&path, &spath)?; |
441 | let metadata = fs::symlink_metadata(&spath)?; | |
ea8adc8c XL |
442 | let smtime = FileTime::from_last_modification_time(&metadata); |
443 | ||
74b04a01 | 444 | set_file_times(&spath, atime, mtime)?; |
ea8adc8c | 445 | |
74b04a01 | 446 | let metadata = fs::metadata(&path)?; |
ea8adc8c XL |
447 | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
448 | assert_eq!(mtime, cur_mtime); | |
449 | ||
74b04a01 | 450 | let metadata = fs::symlink_metadata(&spath)?; |
ea8adc8c XL |
451 | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
452 | assert_eq!(smtime, cur_mtime); | |
453 | ||
74b04a01 | 454 | set_file_times(&spath, atime, new_mtime)?; |
ea8adc8c | 455 | |
74b04a01 | 456 | let metadata = fs::metadata(&path)?; |
ea8adc8c XL |
457 | let mtime = FileTime::from_last_modification_time(&metadata); |
458 | assert_eq!(mtime, new_mtime); | |
459 | ||
74b04a01 | 460 | let metadata = fs::symlink_metadata(&spath)?; |
ea8adc8c XL |
461 | let mtime = FileTime::from_last_modification_time(&metadata); |
462 | assert_eq!(mtime, smtime); | |
74b04a01 | 463 | Ok(()) |
ea8adc8c XL |
464 | } |
465 | ||
83c7162d XL |
466 | #[test] |
467 | fn set_file_times_pre_unix_epoch_test() { | |
74b04a01 | 468 | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
83c7162d XL |
469 | let path = td.path().join("foo.txt"); |
470 | File::create(&path).unwrap(); | |
471 | ||
472 | let metadata = fs::metadata(&path).unwrap(); | |
473 | let mtime = FileTime::from_last_modification_time(&metadata); | |
474 | let atime = FileTime::from_last_access_time(&metadata); | |
475 | set_file_times(&path, atime, mtime).unwrap(); | |
476 | ||
477 | let new_mtime = FileTime::from_unix_time(-10_000, 0); | |
478 | set_file_times(&path, atime, new_mtime).unwrap(); | |
479 | ||
480 | let metadata = fs::metadata(&path).unwrap(); | |
481 | let mtime = FileTime::from_last_modification_time(&metadata); | |
482 | assert_eq!(mtime, new_mtime); | |
483 | } | |
484 | ||
485 | #[test] | |
486 | #[cfg(windows)] | |
487 | fn set_file_times_pre_windows_epoch_test() { | |
74b04a01 | 488 | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
83c7162d XL |
489 | let path = td.path().join("foo.txt"); |
490 | File::create(&path).unwrap(); | |
491 | ||
492 | let metadata = fs::metadata(&path).unwrap(); | |
493 | let mtime = FileTime::from_last_modification_time(&metadata); | |
494 | let atime = FileTime::from_last_access_time(&metadata); | |
495 | set_file_times(&path, atime, mtime).unwrap(); | |
496 | ||
497 | let new_mtime = FileTime::from_unix_time(-12_000_000_000, 0); | |
498 | assert!(set_file_times(&path, atime, new_mtime).is_err()); | |
499 | } | |
500 | ||
ea8adc8c XL |
501 | #[test] |
502 | fn set_symlink_file_times_test() { | |
74b04a01 | 503 | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
ea8adc8c XL |
504 | let path = td.path().join("foo.txt"); |
505 | File::create(&path).unwrap(); | |
506 | ||
507 | let metadata = fs::metadata(&path).unwrap(); | |
508 | let mtime = FileTime::from_last_modification_time(&metadata); | |
509 | let atime = FileTime::from_last_access_time(&metadata); | |
510 | set_symlink_file_times(&path, atime, mtime).unwrap(); | |
511 | ||
83c7162d | 512 | let new_mtime = FileTime::from_unix_time(10_000, 0); |
ea8adc8c XL |
513 | set_symlink_file_times(&path, atime, new_mtime).unwrap(); |
514 | ||
515 | let metadata = fs::metadata(&path).unwrap(); | |
516 | let mtime = FileTime::from_last_modification_time(&metadata); | |
517 | assert_eq!(mtime, new_mtime); | |
518 | ||
519 | let spath = td.path().join("bar.txt"); | |
520 | make_symlink(&path, &spath).unwrap(); | |
521 | ||
522 | let metadata = fs::symlink_metadata(&spath).unwrap(); | |
523 | let smtime = FileTime::from_last_modification_time(&metadata); | |
524 | let satime = FileTime::from_last_access_time(&metadata); | |
525 | set_symlink_file_times(&spath, smtime, satime).unwrap(); | |
526 | ||
527 | let metadata = fs::metadata(&path).unwrap(); | |
528 | let mtime = FileTime::from_last_modification_time(&metadata); | |
529 | assert_eq!(mtime, new_mtime); | |
530 | ||
83c7162d | 531 | let new_smtime = FileTime::from_unix_time(20_000, 0); |
ea8adc8c XL |
532 | set_symlink_file_times(&spath, atime, new_smtime).unwrap(); |
533 | ||
534 | let metadata = fs::metadata(&spath).unwrap(); | |
535 | let mtime = FileTime::from_last_modification_time(&metadata); | |
536 | assert_eq!(mtime, new_mtime); | |
537 | ||
538 | let metadata = fs::symlink_metadata(&spath).unwrap(); | |
539 | let mtime = FileTime::from_last_modification_time(&metadata); | |
540 | assert_eq!(mtime, new_smtime); | |
476ff2be | 541 | } |
74b04a01 XL |
542 | |
543 | #[test] | |
544 | fn set_single_time_test() { | |
545 | use super::{set_file_atime, set_file_mtime}; | |
546 | ||
547 | let td = Builder::new().prefix("filetime").tempdir().unwrap(); | |
548 | let path = td.path().join("foo.txt"); | |
549 | File::create(&path).unwrap(); | |
550 | ||
551 | let metadata = fs::metadata(&path).unwrap(); | |
552 | let mtime = FileTime::from_last_modification_time(&metadata); | |
553 | let atime = FileTime::from_last_access_time(&metadata); | |
554 | set_file_times(&path, atime, mtime).unwrap(); | |
555 | ||
556 | let new_mtime = FileTime::from_unix_time(10_000, 0); | |
557 | set_file_mtime(&path, new_mtime).unwrap(); | |
558 | ||
559 | let metadata = fs::metadata(&path).unwrap(); | |
560 | let mtime = FileTime::from_last_modification_time(&metadata); | |
561 | assert_eq!(mtime, new_mtime, "modification time should be updated"); | |
562 | assert_eq!( | |
563 | atime, | |
564 | FileTime::from_last_access_time(&metadata), | |
565 | "access time should not be updated", | |
566 | ); | |
567 | ||
568 | let new_atime = FileTime::from_unix_time(20_000, 0); | |
569 | set_file_atime(&path, new_atime).unwrap(); | |
570 | ||
571 | let metadata = fs::metadata(&path).unwrap(); | |
572 | let atime = FileTime::from_last_access_time(&metadata); | |
573 | assert_eq!(atime, new_atime, "access time should be updated"); | |
574 | assert_eq!( | |
575 | mtime, | |
576 | FileTime::from_last_modification_time(&metadata), | |
577 | "modification time should not be updated" | |
578 | ); | |
579 | } | |
476ff2be | 580 | } |