/rust/registry/src/index.crates.io-1949cf8c6b5b557f/filetime-0.2.26/src/lib.rs
Line | Count | Source |
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 | | //! |
8 | | //! Add this to your `Cargo.toml`: |
9 | | //! |
10 | | //! ```toml |
11 | | //! [dependencies] |
12 | | //! filetime = "0.2" |
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 |
30 | | //! println!("{}", mtime.unix_seconds()); |
31 | | //! println!("{}", mtime.nanoseconds()); |
32 | | //! |
33 | | //! // Print the platform-specific value of seconds |
34 | | //! println!("{}", mtime.seconds()); |
35 | | //! ``` |
36 | | |
37 | | use std::fmt; |
38 | | use std::fs; |
39 | | use std::io; |
40 | | use std::path::Path; |
41 | | use std::time::{Duration, SystemTime, UNIX_EPOCH}; |
42 | | |
43 | | cfg_if::cfg_if! { |
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; |
50 | | } else if #[cfg(all(target_family = "wasm", not(target_os = "emscripten")))] { |
51 | | #[path = "wasm.rs"] |
52 | | mod imp; |
53 | | } else { |
54 | | #[path = "unix/mod.rs"] |
55 | | mod imp; |
56 | | } |
57 | | } |
58 | | |
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 { |
66 | | seconds: i64, |
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 | 0 | pub const fn zero() -> FileTime { |
75 | 0 | FileTime { |
76 | 0 | seconds: 0, |
77 | 0 | nanos: 0, |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | 0 | const fn emulate_second_only_system(self) -> FileTime { |
82 | 0 | if cfg!(emulate_second_only_system) { |
83 | 0 | FileTime { |
84 | 0 | seconds: self.seconds, |
85 | 0 | nanos: 0, |
86 | 0 | } |
87 | | } else { |
88 | 0 | self |
89 | | } |
90 | 0 | } |
91 | | |
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 | 0 | pub fn now() -> FileTime { |
108 | 0 | FileTime::from_system_time(SystemTime::now()) |
109 | 0 | } |
110 | | |
111 | | /// Creates a new instance of `FileTime` with a number of seconds and |
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. |
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. |
121 | 0 | pub const fn from_unix_time(seconds: i64, nanos: u32) -> FileTime { |
122 | | FileTime { |
123 | 0 | seconds: seconds + if cfg!(windows) { 11644473600 } else { 0 }, |
124 | 0 | nanos, |
125 | | } |
126 | 0 | .emulate_second_only_system() |
127 | 0 | } |
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 | 0 | pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { |
135 | 0 | imp::from_last_modification_time(meta).emulate_second_only_system() |
136 | 0 | } |
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 | 0 | pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { |
144 | 0 | imp::from_last_access_time(meta).emulate_second_only_system() |
145 | 0 | } |
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 | 0 | pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> { |
155 | 0 | imp::from_creation_time(meta).map(|x| x.emulate_second_only_system()) |
156 | 0 | } |
157 | | |
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 | 0 | pub fn from_system_time(time: SystemTime) -> FileTime { |
164 | 0 | let epoch = if cfg!(windows) { |
165 | 0 | UNIX_EPOCH - Duration::from_secs(11644473600) |
166 | | } else { |
167 | 0 | UNIX_EPOCH |
168 | | }; |
169 | | |
170 | 0 | time.duration_since(epoch) |
171 | 0 | .map(|d| FileTime { |
172 | 0 | seconds: d.as_secs() as i64, |
173 | 0 | nanos: d.subsec_nanos(), |
174 | 0 | }) |
175 | 0 | .unwrap_or_else(|e| { |
176 | 0 | let until_epoch = e.duration(); |
177 | 0 | let (sec_offset, nanos) = if until_epoch.subsec_nanos() == 0 { |
178 | 0 | (0, 0) |
179 | | } else { |
180 | 0 | (-1, 1_000_000_000 - until_epoch.subsec_nanos()) |
181 | | }; |
182 | | |
183 | 0 | FileTime { |
184 | 0 | seconds: -1 * until_epoch.as_secs() as i64 + sec_offset, |
185 | 0 | nanos, |
186 | 0 | } |
187 | 0 | }) |
188 | 0 | .emulate_second_only_system() |
189 | 0 | } |
190 | | |
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. |
196 | 0 | pub const fn seconds(&self) -> i64 { |
197 | 0 | self.seconds |
198 | 0 | } |
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. |
205 | 0 | pub const fn unix_seconds(&self) -> i64 { |
206 | 0 | self.seconds - if cfg!(windows) { 11644473600 } else { 0 } |
207 | 0 | } |
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. |
214 | 0 | pub const fn nanoseconds(&self) -> u32 { |
215 | 0 | self.nanos |
216 | 0 | } |
217 | | } |
218 | | |
219 | | impl fmt::Display for FileTime { |
220 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
221 | 0 | write!(f, "{}.{:09}s", self.seconds, self.nanos) |
222 | 0 | } |
223 | | } |
224 | | |
225 | | impl From<SystemTime> for FileTime { |
226 | 0 | fn from(time: SystemTime) -> FileTime { |
227 | 0 | FileTime::from_system_time(time) |
228 | 0 | } |
229 | | } |
230 | | |
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. |
235 | 0 | pub fn set_file_times<P>(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> |
236 | 0 | where |
237 | 0 | P: AsRef<Path>, |
238 | | { |
239 | 0 | imp::set_file_times(p.as_ref(), atime, mtime) |
240 | 0 | } |
241 | | |
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 | 0 | pub fn set_file_handle_times( |
249 | 0 | f: &fs::File, |
250 | 0 | atime: Option<FileTime>, |
251 | 0 | mtime: Option<FileTime>, |
252 | 0 | ) -> io::Result<()> { |
253 | 0 | imp::set_file_handle_times(f, atime, mtime) |
254 | 0 | } |
255 | | |
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. |
261 | 0 | pub fn set_symlink_file_times<P>(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> |
262 | 0 | where |
263 | 0 | P: AsRef<Path>, |
264 | | { |
265 | 0 | imp::set_symlink_file_times(p.as_ref(), atime, mtime) |
266 | 0 | } |
267 | | |
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 | 0 | pub fn set_file_mtime<P>(p: P, mtime: FileTime) -> io::Result<()> |
279 | 0 | where |
280 | 0 | P: AsRef<Path>, |
281 | | { |
282 | 0 | imp::set_file_mtime(p.as_ref(), mtime) |
283 | 0 | } |
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 | 0 | pub fn set_file_atime<P>(p: P, atime: FileTime) -> io::Result<()> |
296 | 0 | where |
297 | 0 | P: AsRef<Path>, |
298 | | { |
299 | 0 | imp::set_file_atime(p.as_ref(), atime) |
300 | 0 | } |
301 | | |
302 | | #[cfg(test)] |
303 | | mod tests { |
304 | | use super::{ |
305 | | set_file_atime, set_file_handle_times, set_file_mtime, set_file_times, |
306 | | set_symlink_file_times, FileTime, |
307 | | }; |
308 | | use std::fs::{self, File}; |
309 | | use std::io; |
310 | | use std::path::Path; |
311 | | use std::time::{Duration, UNIX_EPOCH}; |
312 | | use tempfile::Builder; |
313 | | |
314 | | #[cfg(unix)] |
315 | | fn make_symlink_file<P, Q>(src: P, dst: Q) -> io::Result<()> |
316 | | where |
317 | | P: AsRef<Path>, |
318 | | Q: AsRef<Path>, |
319 | | { |
320 | | use std::os::unix::fs::symlink; |
321 | | symlink(src, dst) |
322 | | } |
323 | | |
324 | | #[cfg(windows)] |
325 | | fn make_symlink_file<P, Q>(src: P, dst: Q) -> io::Result<()> |
326 | | where |
327 | | P: AsRef<Path>, |
328 | | Q: AsRef<Path>, |
329 | | { |
330 | | use std::os::windows::fs::symlink_file; |
331 | | symlink_file(src, dst) |
332 | | } |
333 | | |
334 | | #[cfg(unix)] |
335 | | fn make_symlink_dir<P, Q>(src: P, dst: Q) -> io::Result<()> |
336 | | where |
337 | | P: AsRef<Path>, |
338 | | Q: AsRef<Path>, |
339 | | { |
340 | | use std::os::unix::fs::symlink; |
341 | | symlink(src, dst) |
342 | | } |
343 | | |
344 | | #[cfg(windows)] |
345 | | fn make_symlink_dir<P, Q>(src: P, dst: Q) -> io::Result<()> |
346 | | where |
347 | | P: AsRef<Path>, |
348 | | Q: AsRef<Path>, |
349 | | { |
350 | | use std::os::windows::fs::symlink_dir; |
351 | | symlink_dir(src, dst) |
352 | | } |
353 | | |
354 | | #[test] |
355 | | #[cfg(windows)] |
356 | | fn from_unix_time_test() { |
357 | | let time = FileTime::from_unix_time(10, 100_000_000); |
358 | | assert_eq!(11644473610, time.seconds); |
359 | | assert_eq!(100_000_000, time.nanos); |
360 | | |
361 | | let time = FileTime::from_unix_time(-10, 100_000_000); |
362 | | assert_eq!(11644473590, time.seconds); |
363 | | assert_eq!(100_000_000, time.nanos); |
364 | | |
365 | | let time = FileTime::from_unix_time(-12_000_000_000, 0); |
366 | | assert_eq!(-355526400, time.seconds); |
367 | | assert_eq!(0, time.nanos); |
368 | | } |
369 | | |
370 | | #[test] |
371 | | #[cfg(not(windows))] |
372 | | fn from_unix_time_test() { |
373 | | let time = FileTime::from_unix_time(10, 100_000_000); |
374 | | assert_eq!(10, time.seconds); |
375 | | assert_eq!(100_000_000, time.nanos); |
376 | | |
377 | | let time = FileTime::from_unix_time(-10, 100_000_000); |
378 | | assert_eq!(-10, time.seconds); |
379 | | assert_eq!(100_000_000, time.nanos); |
380 | | |
381 | | let time = FileTime::from_unix_time(-12_000_000_000, 0); |
382 | | assert_eq!(-12_000_000_000, time.seconds); |
383 | | assert_eq!(0, time.nanos); |
384 | | } |
385 | | |
386 | | #[test] |
387 | | #[cfg(windows)] |
388 | | fn from_system_time_test() { |
389 | | let time = FileTime::from_system_time(UNIX_EPOCH + Duration::from_secs(10)); |
390 | | assert_eq!(11644473610, time.seconds); |
391 | | assert_eq!(0, time.nanos); |
392 | | |
393 | | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(10)); |
394 | | assert_eq!(11644473590, time.seconds); |
395 | | assert_eq!(0, time.nanos); |
396 | | |
397 | | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_millis(1100)); |
398 | | assert_eq!(11644473598, time.seconds); |
399 | | assert_eq!(900_000_000, time.nanos); |
400 | | |
401 | | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(12_000_000_000)); |
402 | | assert_eq!(-355526400, time.seconds); |
403 | | assert_eq!(0, time.nanos); |
404 | | } |
405 | | |
406 | | #[test] |
407 | | #[cfg(not(windows))] |
408 | | fn from_system_time_test() { |
409 | | let time = FileTime::from_system_time(UNIX_EPOCH + Duration::from_secs(10)); |
410 | | assert_eq!(10, time.seconds); |
411 | | assert_eq!(0, time.nanos); |
412 | | |
413 | | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(10)); |
414 | | assert_eq!(-10, time.seconds); |
415 | | assert_eq!(0, time.nanos); |
416 | | |
417 | | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_millis(1100)); |
418 | | assert_eq!(-2, time.seconds); |
419 | | assert_eq!(900_000_000, time.nanos); |
420 | | |
421 | | let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(12_000_000)); |
422 | | assert_eq!(-12_000_000, time.seconds); |
423 | | assert_eq!(0, time.nanos); |
424 | | } |
425 | | |
426 | | #[test] |
427 | | fn set_file_times_test() -> io::Result<()> { |
428 | | let td = Builder::new().prefix("filetime").tempdir()?; |
429 | | let path = td.path().join("foo.txt"); |
430 | | let mut f = File::create(&path)?; |
431 | | |
432 | | let metadata = fs::metadata(&path)?; |
433 | | let mtime = FileTime::from_last_modification_time(&metadata); |
434 | | let atime = FileTime::from_last_access_time(&metadata); |
435 | | set_file_times(&path, atime, mtime)?; |
436 | | |
437 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
438 | | set_file_times(&path, atime, new_mtime)?; |
439 | | |
440 | | let metadata = fs::metadata(&path)?; |
441 | | let mtime = FileTime::from_last_modification_time(&metadata); |
442 | | assert_eq!(mtime, new_mtime, "modification should be updated"); |
443 | | |
444 | | // Update just mtime |
445 | | let new_mtime = FileTime::from_unix_time(20_000, 0); |
446 | | set_file_handle_times(&mut f, None, Some(new_mtime))?; |
447 | | let metadata = f.metadata()?; |
448 | | let mtime = FileTime::from_last_modification_time(&metadata); |
449 | | assert_eq!(mtime, new_mtime, "modification time should be updated"); |
450 | | let new_atime = FileTime::from_last_access_time(&metadata); |
451 | | assert_eq!(atime, new_atime, "accessed time should not be updated"); |
452 | | |
453 | | // Update just atime |
454 | | let new_atime = FileTime::from_unix_time(30_000, 0); |
455 | | set_file_handle_times(&mut f, Some(new_atime), None)?; |
456 | | let metadata = f.metadata()?; |
457 | | let mtime = FileTime::from_last_modification_time(&metadata); |
458 | | assert_eq!(mtime, new_mtime, "modification time should not be updated"); |
459 | | let atime = FileTime::from_last_access_time(&metadata); |
460 | | assert_eq!(atime, new_atime, "accessed time should be updated"); |
461 | | |
462 | | let spath = td.path().join("bar.txt"); |
463 | | make_symlink_file(&path, &spath)?; |
464 | | let metadata = fs::symlink_metadata(&spath)?; |
465 | | let smtime = FileTime::from_last_modification_time(&metadata); |
466 | | |
467 | | set_file_times(&spath, atime, mtime)?; |
468 | | |
469 | | let metadata = fs::metadata(&path)?; |
470 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
471 | | assert_eq!(mtime, cur_mtime); |
472 | | |
473 | | let metadata = fs::symlink_metadata(&spath)?; |
474 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
475 | | assert_eq!(smtime, cur_mtime); |
476 | | |
477 | | set_file_times(&spath, atime, new_mtime)?; |
478 | | |
479 | | let metadata = fs::metadata(&path)?; |
480 | | let mtime = FileTime::from_last_modification_time(&metadata); |
481 | | assert_eq!(mtime, new_mtime); |
482 | | |
483 | | let metadata = fs::symlink_metadata(&spath)?; |
484 | | let mtime = FileTime::from_last_modification_time(&metadata); |
485 | | assert_eq!(mtime, smtime); |
486 | | Ok(()) |
487 | | } |
488 | | |
489 | | #[test] |
490 | | fn set_dir_times_test() -> io::Result<()> { |
491 | | let td = Builder::new().prefix("filetime").tempdir()?; |
492 | | let path = td.path().join("foo"); |
493 | | fs::create_dir(&path)?; |
494 | | |
495 | | let metadata = fs::metadata(&path)?; |
496 | | let mtime = FileTime::from_last_modification_time(&metadata); |
497 | | let atime = FileTime::from_last_access_time(&metadata); |
498 | | set_file_times(&path, atime, mtime)?; |
499 | | |
500 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
501 | | set_file_times(&path, atime, new_mtime)?; |
502 | | |
503 | | let metadata = fs::metadata(&path)?; |
504 | | let mtime = FileTime::from_last_modification_time(&metadata); |
505 | | assert_eq!(mtime, new_mtime, "modification should be updated"); |
506 | | |
507 | | // Update just mtime |
508 | | let new_mtime = FileTime::from_unix_time(20_000, 0); |
509 | | set_file_mtime(&path, new_mtime)?; |
510 | | let metadata = fs::metadata(&path)?; |
511 | | let mtime = FileTime::from_last_modification_time(&metadata); |
512 | | assert_eq!(mtime, new_mtime, "modification time should be updated"); |
513 | | let new_atime = FileTime::from_last_access_time(&metadata); |
514 | | assert_eq!(atime, new_atime, "accessed time should not be updated"); |
515 | | |
516 | | // Update just atime |
517 | | let new_atime = FileTime::from_unix_time(30_000, 0); |
518 | | set_file_atime(&path, new_atime)?; |
519 | | let metadata = fs::metadata(&path)?; |
520 | | let mtime = FileTime::from_last_modification_time(&metadata); |
521 | | assert_eq!(mtime, new_mtime, "modification time should not be updated"); |
522 | | let atime = FileTime::from_last_access_time(&metadata); |
523 | | assert_eq!(atime, new_atime, "accessed time should be updated"); |
524 | | |
525 | | let spath = td.path().join("bar"); |
526 | | make_symlink_dir(&path, &spath)?; |
527 | | let metadata = fs::symlink_metadata(&spath)?; |
528 | | let smtime = FileTime::from_last_modification_time(&metadata); |
529 | | |
530 | | set_file_times(&spath, atime, mtime)?; |
531 | | |
532 | | let metadata = fs::metadata(&path)?; |
533 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
534 | | assert_eq!(mtime, cur_mtime); |
535 | | |
536 | | let metadata = fs::symlink_metadata(&spath)?; |
537 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
538 | | assert_eq!(smtime, cur_mtime); |
539 | | |
540 | | set_file_times(&spath, atime, new_mtime)?; |
541 | | |
542 | | let metadata = fs::metadata(&path)?; |
543 | | let mtime = FileTime::from_last_modification_time(&metadata); |
544 | | assert_eq!(mtime, new_mtime); |
545 | | |
546 | | let metadata = fs::symlink_metadata(&spath)?; |
547 | | let mtime = FileTime::from_last_modification_time(&metadata); |
548 | | assert_eq!(mtime, smtime); |
549 | | Ok(()) |
550 | | } |
551 | | |
552 | | #[test] |
553 | | fn set_file_times_pre_unix_epoch_test() { |
554 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
555 | | let path = td.path().join("foo.txt"); |
556 | | File::create(&path).unwrap(); |
557 | | |
558 | | let metadata = fs::metadata(&path).unwrap(); |
559 | | let mtime = FileTime::from_last_modification_time(&metadata); |
560 | | let atime = FileTime::from_last_access_time(&metadata); |
561 | | set_file_times(&path, atime, mtime).unwrap(); |
562 | | |
563 | | let new_mtime = FileTime::from_unix_time(-10_000, 0); |
564 | | if cfg!(target_os = "aix") { |
565 | | // On AIX, os checks if the unix timestamp is valid. |
566 | | let result = set_file_times(&path, atime, new_mtime); |
567 | | assert!(result.is_err()); |
568 | | assert!(result.err().unwrap().kind() == std::io::ErrorKind::InvalidInput); |
569 | | } else { |
570 | | set_file_times(&path, atime, new_mtime).unwrap(); |
571 | | |
572 | | let metadata = fs::metadata(&path).unwrap(); |
573 | | let mtime = FileTime::from_last_modification_time(&metadata); |
574 | | assert_eq!(mtime, new_mtime); |
575 | | } |
576 | | } |
577 | | |
578 | | #[test] |
579 | | #[cfg(windows)] |
580 | | fn set_file_times_pre_windows_epoch_test() { |
581 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
582 | | let path = td.path().join("foo.txt"); |
583 | | File::create(&path).unwrap(); |
584 | | |
585 | | let metadata = fs::metadata(&path).unwrap(); |
586 | | let mtime = FileTime::from_last_modification_time(&metadata); |
587 | | let atime = FileTime::from_last_access_time(&metadata); |
588 | | set_file_times(&path, atime, mtime).unwrap(); |
589 | | |
590 | | let new_mtime = FileTime::from_unix_time(-12_000_000_000, 0); |
591 | | assert!(set_file_times(&path, atime, new_mtime).is_err()); |
592 | | } |
593 | | |
594 | | #[test] |
595 | | fn set_symlink_file_times_test() { |
596 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
597 | | let path = td.path().join("foo.txt"); |
598 | | File::create(&path).unwrap(); |
599 | | |
600 | | let metadata = fs::metadata(&path).unwrap(); |
601 | | let mtime = FileTime::from_last_modification_time(&metadata); |
602 | | let atime = FileTime::from_last_access_time(&metadata); |
603 | | set_symlink_file_times(&path, atime, mtime).unwrap(); |
604 | | |
605 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
606 | | set_symlink_file_times(&path, atime, new_mtime).unwrap(); |
607 | | |
608 | | let metadata = fs::metadata(&path).unwrap(); |
609 | | let mtime = FileTime::from_last_modification_time(&metadata); |
610 | | assert_eq!(mtime, new_mtime); |
611 | | |
612 | | let spath = td.path().join("bar.txt"); |
613 | | make_symlink_file(&path, &spath).unwrap(); |
614 | | |
615 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
616 | | let smtime = FileTime::from_last_modification_time(&metadata); |
617 | | let satime = FileTime::from_last_access_time(&metadata); |
618 | | set_symlink_file_times(&spath, smtime, satime).unwrap(); |
619 | | |
620 | | let metadata = fs::metadata(&path).unwrap(); |
621 | | let mtime = FileTime::from_last_modification_time(&metadata); |
622 | | assert_eq!(mtime, new_mtime); |
623 | | |
624 | | let new_smtime = FileTime::from_unix_time(20_000, 0); |
625 | | set_symlink_file_times(&spath, atime, new_smtime).unwrap(); |
626 | | |
627 | | let metadata = fs::metadata(&spath).unwrap(); |
628 | | let mtime = FileTime::from_last_modification_time(&metadata); |
629 | | assert_eq!(mtime, new_mtime); |
630 | | |
631 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
632 | | let mtime = FileTime::from_last_modification_time(&metadata); |
633 | | assert_eq!(mtime, new_smtime); |
634 | | } |
635 | | |
636 | | #[test] |
637 | | fn set_symlink_dir_times_test() { |
638 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
639 | | let path = td.path().join("foo"); |
640 | | fs::create_dir(&path).unwrap(); |
641 | | |
642 | | let metadata = fs::metadata(&path).unwrap(); |
643 | | let mtime = FileTime::from_last_modification_time(&metadata); |
644 | | let atime = FileTime::from_last_access_time(&metadata); |
645 | | set_symlink_file_times(&path, atime, mtime).unwrap(); |
646 | | |
647 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
648 | | set_symlink_file_times(&path, atime, new_mtime).unwrap(); |
649 | | |
650 | | let metadata = fs::metadata(&path).unwrap(); |
651 | | let mtime = FileTime::from_last_modification_time(&metadata); |
652 | | assert_eq!(mtime, new_mtime); |
653 | | |
654 | | let spath = td.path().join("bar"); |
655 | | make_symlink_dir(&path, &spath).unwrap(); |
656 | | |
657 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
658 | | let smtime = FileTime::from_last_modification_time(&metadata); |
659 | | let satime = FileTime::from_last_access_time(&metadata); |
660 | | set_symlink_file_times(&spath, smtime, satime).unwrap(); |
661 | | |
662 | | let metadata = fs::metadata(&path).unwrap(); |
663 | | let mtime = FileTime::from_last_modification_time(&metadata); |
664 | | assert_eq!(mtime, new_mtime); |
665 | | |
666 | | let new_smtime = FileTime::from_unix_time(20_000, 0); |
667 | | set_symlink_file_times(&spath, atime, new_smtime).unwrap(); |
668 | | |
669 | | let metadata = fs::metadata(&spath).unwrap(); |
670 | | let mtime = FileTime::from_last_modification_time(&metadata); |
671 | | assert_eq!(mtime, new_mtime); |
672 | | |
673 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
674 | | let mtime = FileTime::from_last_modification_time(&metadata); |
675 | | assert_eq!(mtime, new_smtime); |
676 | | } |
677 | | |
678 | | #[test] |
679 | | fn set_single_time_test() { |
680 | | use super::{set_file_atime, set_file_mtime}; |
681 | | |
682 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
683 | | let path = td.path().join("foo.txt"); |
684 | | File::create(&path).unwrap(); |
685 | | |
686 | | let metadata = fs::metadata(&path).unwrap(); |
687 | | let mtime = FileTime::from_last_modification_time(&metadata); |
688 | | let atime = FileTime::from_last_access_time(&metadata); |
689 | | set_file_times(&path, atime, mtime).unwrap(); |
690 | | |
691 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
692 | | set_file_mtime(&path, new_mtime).unwrap(); |
693 | | |
694 | | let metadata = fs::metadata(&path).unwrap(); |
695 | | let mtime = FileTime::from_last_modification_time(&metadata); |
696 | | assert_eq!(mtime, new_mtime, "modification time should be updated"); |
697 | | assert_eq!( |
698 | | atime, |
699 | | FileTime::from_last_access_time(&metadata), |
700 | | "access time should not be updated", |
701 | | ); |
702 | | |
703 | | let new_atime = FileTime::from_unix_time(20_000, 0); |
704 | | set_file_atime(&path, new_atime).unwrap(); |
705 | | |
706 | | let metadata = fs::metadata(&path).unwrap(); |
707 | | let atime = FileTime::from_last_access_time(&metadata); |
708 | | assert_eq!(atime, new_atime, "access time should be updated"); |
709 | | assert_eq!( |
710 | | mtime, |
711 | | FileTime::from_last_modification_time(&metadata), |
712 | | "modification time should not be updated" |
713 | | ); |
714 | | } |
715 | | } |