/rust/registry/src/index.crates.io-1949cf8c6b5b557f/filetime-0.2.29/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 | 15.0k | const fn emulate_second_only_system(self) -> FileTime { |
82 | 15.0k | if cfg!(emulate_second_only_system) { |
83 | 0 | FileTime { |
84 | 0 | seconds: self.seconds, |
85 | 0 | nanos: 0, |
86 | 0 | } |
87 | | } else { |
88 | 15.0k | self |
89 | | } |
90 | 15.0k | } |
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 | 15.0k | pub const fn from_unix_time(seconds: i64, nanos: u32) -> FileTime { |
122 | | FileTime { |
123 | 15.0k | seconds: seconds + if cfg!(windows) { 11644473600 } else { 0 }, |
124 | 15.0k | nanos, |
125 | | } |
126 | 15.0k | .emulate_second_only_system() |
127 | 15.0k | } |
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 | | impl From<FileTime> for SystemTime { |
232 | 0 | fn from(time: FileTime) -> SystemTime { |
233 | 0 | let seconds = time.unix_seconds(); |
234 | 0 | if seconds < 0 { |
235 | 0 | SystemTime::UNIX_EPOCH - Duration::from_secs(-seconds as u64) |
236 | 0 | + Duration::from_nanos(time.nanoseconds() as u64) |
237 | | } else { |
238 | 0 | SystemTime::UNIX_EPOCH + Duration::new(seconds as u64, time.nanoseconds()) |
239 | | } |
240 | 0 | } |
241 | | } |
242 | | |
243 | | /// Set the last access and modification times for a file on the filesystem. |
244 | | /// |
245 | | /// This function will set the `atime` and `mtime` metadata fields for a file |
246 | | /// on the local filesystem, returning any error encountered. |
247 | 0 | pub fn set_file_times<P>(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> |
248 | 0 | where |
249 | 0 | P: AsRef<Path>, |
250 | | { |
251 | 0 | imp::open(p.as_ref())?.set_times( |
252 | 0 | fs::FileTimes::new() |
253 | 0 | .set_accessed(atime.into()) |
254 | 0 | .set_modified(mtime.into()), |
255 | | ) |
256 | 0 | } |
257 | | |
258 | | /// Set the last access and modification times for a file handle. |
259 | | /// |
260 | | /// This function will either or both of the `atime` and `mtime` metadata |
261 | | /// fields for a file handle , returning any error encountered. If `None` is |
262 | | /// specified then the time won't be updated. If `None` is specified for both |
263 | | /// options then no action is taken. |
264 | 0 | pub fn set_file_handle_times( |
265 | 0 | f: &fs::File, |
266 | 0 | atime: Option<FileTime>, |
267 | 0 | mtime: Option<FileTime>, |
268 | 0 | ) -> io::Result<()> { |
269 | 0 | let mut times = fs::FileTimes::new(); |
270 | 0 | if let Some(t) = atime { |
271 | 0 | times = times.set_accessed(t.into()); |
272 | 0 | } |
273 | 0 | if let Some(t) = mtime { |
274 | 0 | times = times.set_modified(t.into()); |
275 | 0 | } |
276 | 0 | f.set_times(times) |
277 | 0 | } |
278 | | |
279 | | /// Set the last access and modification times for a file on the filesystem. |
280 | | /// This function does not follow symlink. |
281 | | /// |
282 | | /// This function will set the `atime` and `mtime` metadata fields for a file |
283 | | /// on the local filesystem, returning any error encountered. |
284 | 0 | pub fn set_symlink_file_times<P>(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> |
285 | 0 | where |
286 | 0 | P: AsRef<Path>, |
287 | | { |
288 | 0 | imp::set_symlink_file_times(p.as_ref(), atime, mtime) |
289 | 0 | } |
290 | | |
291 | | /// Set the last modification time for a file on the filesystem. |
292 | | /// |
293 | | /// This function will set the `mtime` metadata field for a file on the local |
294 | | /// filesystem, returning any error encountered. |
295 | | /// |
296 | | /// # Platform support |
297 | | /// |
298 | | /// Where supported this will attempt to issue just one syscall to update only |
299 | | /// the `mtime`, but where not supported this may issue one syscall to learn the |
300 | | /// existing `atime` so only the `mtime` can be configured. |
301 | 0 | pub fn set_file_mtime<P>(p: P, mtime: FileTime) -> io::Result<()> |
302 | 0 | where |
303 | 0 | P: AsRef<Path>, |
304 | | { |
305 | 0 | imp::open(p.as_ref())?.set_times(fs::FileTimes::new().set_modified(mtime.into())) |
306 | 0 | } |
307 | | |
308 | | /// Set the last access time for a file on the filesystem. |
309 | | /// |
310 | | /// This function will set the `atime` metadata field for a file on the local |
311 | | /// filesystem, returning any error encountered. |
312 | | /// |
313 | | /// # Platform support |
314 | | /// |
315 | | /// Where supported this will attempt to issue just one syscall to update only |
316 | | /// the `atime`, but where not supported this may issue one syscall to learn the |
317 | | /// existing `mtime` so only the `atime` can be configured. |
318 | 0 | pub fn set_file_atime<P>(p: P, atime: FileTime) -> io::Result<()> |
319 | 0 | where |
320 | 0 | P: AsRef<Path>, |
321 | | { |
322 | 0 | imp::open(p.as_ref())?.set_times(fs::FileTimes::new().set_accessed(atime.into())) |
323 | 0 | } |
324 | | |
325 | | #[cfg(test)] |
326 | | mod tests { |
327 | | use super::{ |
328 | | set_file_atime, set_file_handle_times, set_file_mtime, set_file_times, |
329 | | set_symlink_file_times, FileTime, |
330 | | }; |
331 | | use std::fs::{self, File}; |
332 | | use std::io; |
333 | | use std::path::Path; |
334 | | use std::time::{Duration, UNIX_EPOCH}; |
335 | | use tempfile::Builder; |
336 | | |
337 | | #[cfg(unix)] |
338 | | fn make_symlink_file<P, Q>(src: P, dst: Q) -> io::Result<()> |
339 | | where |
340 | | P: AsRef<Path>, |
341 | | Q: AsRef<Path>, |
342 | | { |
343 | | use std::os::unix::fs::symlink; |
344 | | symlink(src, dst) |
345 | | } |
346 | | |
347 | | #[cfg(windows)] |
348 | | fn make_symlink_file<P, Q>(src: P, dst: Q) -> io::Result<()> |
349 | | where |
350 | | P: AsRef<Path>, |
351 | | Q: AsRef<Path>, |
352 | | { |
353 | | use std::os::windows::fs::symlink_file; |
354 | | symlink_file(src, dst) |
355 | | } |
356 | | |
357 | | #[cfg(unix)] |
358 | | fn make_symlink_dir<P, Q>(src: P, dst: Q) -> io::Result<()> |
359 | | where |
360 | | P: AsRef<Path>, |
361 | | Q: AsRef<Path>, |
362 | | { |
363 | | use std::os::unix::fs::symlink; |
364 | | symlink(src, dst) |
365 | | } |
366 | | |
367 | | #[cfg(windows)] |
368 | | fn make_symlink_dir<P, Q>(src: P, dst: Q) -> io::Result<()> |
369 | | where |
370 | | P: AsRef<Path>, |
371 | | Q: AsRef<Path>, |
372 | | { |
373 | | use std::os::windows::fs::symlink_dir; |
374 | | symlink_dir(src, dst) |
375 | | } |
376 | | |
377 | | #[test] |
378 | | #[cfg(windows)] |
379 | | fn from_unix_time_test() { |
380 | | let time = FileTime::from_unix_time(10, 100_000_000); |
381 | | assert_eq!(11644473610, time.seconds); |
382 | | assert_eq!(100_000_000, time.nanos); |
383 | | |
384 | | let time = FileTime::from_unix_time(-10, 100_000_000); |
385 | | assert_eq!(11644473590, time.seconds); |
386 | | assert_eq!(100_000_000, time.nanos); |
387 | | |
388 | | let time = FileTime::from_unix_time(-12_000_000_000, 0); |
389 | | assert_eq!(-355526400, time.seconds); |
390 | | assert_eq!(0, time.nanos); |
391 | | } |
392 | | |
393 | | #[test] |
394 | | #[cfg(not(windows))] |
395 | | fn from_unix_time_test() { |
396 | | let time = FileTime::from_unix_time(10, 100_000_000); |
397 | | assert_eq!(10, time.seconds); |
398 | | assert_eq!(100_000_000, time.nanos); |
399 | | |
400 | | let time = FileTime::from_unix_time(-10, 100_000_000); |
401 | | assert_eq!(-10, time.seconds); |
402 | | assert_eq!(100_000_000, time.nanos); |
403 | | |
404 | | let time = FileTime::from_unix_time(-12_000_000_000, 0); |
405 | | assert_eq!(-12_000_000_000, time.seconds); |
406 | | assert_eq!(0, time.nanos); |
407 | | } |
408 | | |
409 | | #[test] |
410 | | #[cfg(windows)] |
411 | | fn to_from_system_time_test() { |
412 | | let systime = UNIX_EPOCH + Duration::from_secs(10); |
413 | | let time = FileTime::from_system_time(systime); |
414 | | assert_eq!(11644473610, time.seconds); |
415 | | assert_eq!(0, time.nanos); |
416 | | assert_eq!(systime, time.into()); |
417 | | |
418 | | let systime = UNIX_EPOCH - Duration::from_secs(10); |
419 | | let time = FileTime::from_system_time(systime); |
420 | | assert_eq!(11644473590, time.seconds); |
421 | | assert_eq!(0, time.nanos); |
422 | | assert_eq!(systime, time.into()); |
423 | | |
424 | | let systime = UNIX_EPOCH - Duration::from_millis(1100); |
425 | | let time = FileTime::from_system_time(systime); |
426 | | assert_eq!(11644473598, time.seconds); |
427 | | assert_eq!(900_000_000, time.nanos); |
428 | | assert_eq!(systime, time.into()); |
429 | | } |
430 | | |
431 | | #[test] |
432 | | #[cfg(not(windows))] |
433 | | fn to_from_system_time_test() { |
434 | | let systime = UNIX_EPOCH + Duration::from_secs(10); |
435 | | let time = FileTime::from_system_time(systime); |
436 | | assert_eq!(10, time.seconds); |
437 | | assert_eq!(0, time.nanos); |
438 | | assert_eq!(systime, time.into()); |
439 | | |
440 | | let systime = UNIX_EPOCH - Duration::from_secs(10); |
441 | | let time = FileTime::from_system_time(systime); |
442 | | assert_eq!(-10, time.seconds); |
443 | | assert_eq!(0, time.nanos); |
444 | | assert_eq!(systime, time.into()); |
445 | | |
446 | | let systime = UNIX_EPOCH - Duration::from_millis(1100); |
447 | | let time = FileTime::from_system_time(systime); |
448 | | assert_eq!(-2, time.seconds); |
449 | | assert_eq!(900_000_000, time.nanos); |
450 | | assert_eq!(systime, time.into()); |
451 | | |
452 | | let systime = UNIX_EPOCH - Duration::from_secs(12_000_000); |
453 | | let time = FileTime::from_system_time(systime); |
454 | | assert_eq!(-12_000_000, time.seconds); |
455 | | assert_eq!(0, time.nanos); |
456 | | assert_eq!(systime, time.into()); |
457 | | } |
458 | | |
459 | | #[test] |
460 | | fn set_file_times_test() -> io::Result<()> { |
461 | | let td = Builder::new().prefix("filetime").tempdir()?; |
462 | | let path = td.path().join("foo.txt"); |
463 | | let mut f = File::create(&path)?; |
464 | | |
465 | | let metadata = fs::metadata(&path)?; |
466 | | let mtime = FileTime::from_last_modification_time(&metadata); |
467 | | let atime = FileTime::from_last_access_time(&metadata); |
468 | | set_file_times(&path, atime, mtime)?; |
469 | | |
470 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
471 | | set_file_times(&path, atime, new_mtime)?; |
472 | | |
473 | | let metadata = fs::metadata(&path)?; |
474 | | let mtime = FileTime::from_last_modification_time(&metadata); |
475 | | assert_eq!(mtime, new_mtime, "modification should be updated"); |
476 | | |
477 | | // Update just mtime |
478 | | let new_mtime = FileTime::from_unix_time(20_000, 0); |
479 | | set_file_handle_times(&mut f, None, Some(new_mtime))?; |
480 | | let metadata = f.metadata()?; |
481 | | let mtime = FileTime::from_last_modification_time(&metadata); |
482 | | assert_eq!(mtime, new_mtime, "modification time should be updated"); |
483 | | let new_atime = FileTime::from_last_access_time(&metadata); |
484 | | assert_eq!(atime, new_atime, "accessed time should not be updated"); |
485 | | |
486 | | // Update just atime |
487 | | let new_atime = FileTime::from_unix_time(30_000, 0); |
488 | | set_file_handle_times(&mut f, Some(new_atime), None)?; |
489 | | let metadata = f.metadata()?; |
490 | | let mtime = FileTime::from_last_modification_time(&metadata); |
491 | | assert_eq!(mtime, new_mtime, "modification time should not be updated"); |
492 | | let atime = FileTime::from_last_access_time(&metadata); |
493 | | assert_eq!(atime, new_atime, "accessed time should be updated"); |
494 | | |
495 | | let spath = td.path().join("bar.txt"); |
496 | | make_symlink_file(&path, &spath)?; |
497 | | let metadata = fs::symlink_metadata(&spath)?; |
498 | | let smtime = FileTime::from_last_modification_time(&metadata); |
499 | | |
500 | | set_file_times(&spath, atime, mtime)?; |
501 | | |
502 | | let metadata = fs::metadata(&path)?; |
503 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
504 | | assert_eq!(mtime, cur_mtime); |
505 | | |
506 | | let metadata = fs::symlink_metadata(&spath)?; |
507 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
508 | | assert_eq!(smtime, cur_mtime); |
509 | | |
510 | | set_file_times(&spath, atime, new_mtime)?; |
511 | | |
512 | | let metadata = fs::metadata(&path)?; |
513 | | let mtime = FileTime::from_last_modification_time(&metadata); |
514 | | assert_eq!(mtime, new_mtime); |
515 | | |
516 | | let metadata = fs::symlink_metadata(&spath)?; |
517 | | let mtime = FileTime::from_last_modification_time(&metadata); |
518 | | assert_eq!(mtime, smtime); |
519 | | Ok(()) |
520 | | } |
521 | | |
522 | | #[test] |
523 | | fn set_dir_times_test() -> io::Result<()> { |
524 | | let td = Builder::new().prefix("filetime").tempdir()?; |
525 | | let path = td.path().join("foo"); |
526 | | fs::create_dir(&path)?; |
527 | | |
528 | | let metadata = fs::metadata(&path)?; |
529 | | let mtime = FileTime::from_last_modification_time(&metadata); |
530 | | let atime = FileTime::from_last_access_time(&metadata); |
531 | | set_file_times(&path, atime, mtime)?; |
532 | | |
533 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
534 | | set_file_times(&path, atime, new_mtime)?; |
535 | | |
536 | | let metadata = fs::metadata(&path)?; |
537 | | let mtime = FileTime::from_last_modification_time(&metadata); |
538 | | assert_eq!(mtime, new_mtime, "modification should be updated"); |
539 | | |
540 | | // Update just mtime |
541 | | let new_mtime = FileTime::from_unix_time(20_000, 0); |
542 | | set_file_mtime(&path, new_mtime)?; |
543 | | let metadata = fs::metadata(&path)?; |
544 | | let mtime = FileTime::from_last_modification_time(&metadata); |
545 | | assert_eq!(mtime, new_mtime, "modification time should be updated"); |
546 | | let new_atime = FileTime::from_last_access_time(&metadata); |
547 | | assert_eq!(atime, new_atime, "accessed time should not be updated"); |
548 | | |
549 | | // Update just atime |
550 | | let new_atime = FileTime::from_unix_time(30_000, 0); |
551 | | set_file_atime(&path, new_atime)?; |
552 | | let metadata = fs::metadata(&path)?; |
553 | | let mtime = FileTime::from_last_modification_time(&metadata); |
554 | | assert_eq!(mtime, new_mtime, "modification time should not be updated"); |
555 | | let atime = FileTime::from_last_access_time(&metadata); |
556 | | assert_eq!(atime, new_atime, "accessed time should be updated"); |
557 | | |
558 | | let spath = td.path().join("bar"); |
559 | | make_symlink_dir(&path, &spath)?; |
560 | | let metadata = fs::symlink_metadata(&spath)?; |
561 | | let smtime = FileTime::from_last_modification_time(&metadata); |
562 | | |
563 | | set_file_times(&spath, atime, mtime)?; |
564 | | |
565 | | let metadata = fs::metadata(&path)?; |
566 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
567 | | assert_eq!(mtime, cur_mtime); |
568 | | |
569 | | let metadata = fs::symlink_metadata(&spath)?; |
570 | | let cur_mtime = FileTime::from_last_modification_time(&metadata); |
571 | | assert_eq!(smtime, cur_mtime); |
572 | | |
573 | | set_file_times(&spath, atime, new_mtime)?; |
574 | | |
575 | | let metadata = fs::metadata(&path)?; |
576 | | let mtime = FileTime::from_last_modification_time(&metadata); |
577 | | assert_eq!(mtime, new_mtime); |
578 | | |
579 | | let metadata = fs::symlink_metadata(&spath)?; |
580 | | let mtime = FileTime::from_last_modification_time(&metadata); |
581 | | assert_eq!(mtime, smtime); |
582 | | Ok(()) |
583 | | } |
584 | | |
585 | | #[test] |
586 | | fn set_file_times_pre_unix_epoch_test() { |
587 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
588 | | let path = td.path().join("foo.txt"); |
589 | | File::create(&path).unwrap(); |
590 | | |
591 | | let metadata = fs::metadata(&path).unwrap(); |
592 | | let mtime = FileTime::from_last_modification_time(&metadata); |
593 | | let atime = FileTime::from_last_access_time(&metadata); |
594 | | set_file_times(&path, atime, mtime).unwrap(); |
595 | | |
596 | | let new_mtime = FileTime::from_unix_time(-10_000, 0); |
597 | | if cfg!(target_os = "aix") { |
598 | | // On AIX, os checks if the unix timestamp is valid. |
599 | | let result = set_file_times(&path, atime, new_mtime); |
600 | | assert!(result.is_err()); |
601 | | assert!(result.err().unwrap().kind() == std::io::ErrorKind::InvalidInput); |
602 | | } else { |
603 | | set_file_times(&path, atime, new_mtime).unwrap(); |
604 | | |
605 | | let metadata = fs::metadata(&path).unwrap(); |
606 | | let mtime = FileTime::from_last_modification_time(&metadata); |
607 | | assert_eq!(mtime, new_mtime); |
608 | | } |
609 | | } |
610 | | |
611 | | #[test] |
612 | | #[cfg(windows)] |
613 | | fn set_file_times_pre_windows_epoch_test() { |
614 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
615 | | let path = td.path().join("foo.txt"); |
616 | | File::create(&path).unwrap(); |
617 | | |
618 | | let metadata = fs::metadata(&path).unwrap(); |
619 | | let mtime = FileTime::from_last_modification_time(&metadata); |
620 | | let atime = FileTime::from_last_access_time(&metadata); |
621 | | set_file_times(&path, atime, mtime).unwrap(); |
622 | | } |
623 | | |
624 | | #[test] |
625 | | fn set_symlink_file_times_test() { |
626 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
627 | | let path = td.path().join("foo.txt"); |
628 | | File::create(&path).unwrap(); |
629 | | |
630 | | let metadata = fs::metadata(&path).unwrap(); |
631 | | let mtime = FileTime::from_last_modification_time(&metadata); |
632 | | let atime = FileTime::from_last_access_time(&metadata); |
633 | | set_symlink_file_times(&path, atime, mtime).unwrap(); |
634 | | |
635 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
636 | | set_symlink_file_times(&path, atime, new_mtime).unwrap(); |
637 | | |
638 | | let metadata = fs::metadata(&path).unwrap(); |
639 | | let mtime = FileTime::from_last_modification_time(&metadata); |
640 | | assert_eq!(mtime, new_mtime); |
641 | | |
642 | | let spath = td.path().join("bar.txt"); |
643 | | make_symlink_file(&path, &spath).unwrap(); |
644 | | |
645 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
646 | | let smtime = FileTime::from_last_modification_time(&metadata); |
647 | | let satime = FileTime::from_last_access_time(&metadata); |
648 | | set_symlink_file_times(&spath, smtime, satime).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 new_smtime = FileTime::from_unix_time(20_000, 0); |
655 | | set_symlink_file_times(&spath, atime, new_smtime).unwrap(); |
656 | | |
657 | | let metadata = fs::metadata(&spath).unwrap(); |
658 | | let mtime = FileTime::from_last_modification_time(&metadata); |
659 | | assert_eq!(mtime, new_mtime); |
660 | | |
661 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
662 | | let mtime = FileTime::from_last_modification_time(&metadata); |
663 | | assert_eq!(mtime, new_smtime); |
664 | | } |
665 | | |
666 | | #[test] |
667 | | fn set_symlink_dir_times_test() { |
668 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
669 | | let path = td.path().join("foo"); |
670 | | fs::create_dir(&path).unwrap(); |
671 | | |
672 | | let metadata = fs::metadata(&path).unwrap(); |
673 | | let mtime = FileTime::from_last_modification_time(&metadata); |
674 | | let atime = FileTime::from_last_access_time(&metadata); |
675 | | set_symlink_file_times(&path, atime, mtime).unwrap(); |
676 | | |
677 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
678 | | set_symlink_file_times(&path, atime, new_mtime).unwrap(); |
679 | | |
680 | | let metadata = fs::metadata(&path).unwrap(); |
681 | | let mtime = FileTime::from_last_modification_time(&metadata); |
682 | | assert_eq!(mtime, new_mtime); |
683 | | |
684 | | let spath = td.path().join("bar"); |
685 | | make_symlink_dir(&path, &spath).unwrap(); |
686 | | |
687 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
688 | | let smtime = FileTime::from_last_modification_time(&metadata); |
689 | | let satime = FileTime::from_last_access_time(&metadata); |
690 | | set_symlink_file_times(&spath, smtime, satime).unwrap(); |
691 | | |
692 | | let metadata = fs::metadata(&path).unwrap(); |
693 | | let mtime = FileTime::from_last_modification_time(&metadata); |
694 | | assert_eq!(mtime, new_mtime); |
695 | | |
696 | | let new_smtime = FileTime::from_unix_time(20_000, 0); |
697 | | set_symlink_file_times(&spath, atime, new_smtime).unwrap(); |
698 | | |
699 | | let metadata = fs::metadata(&spath).unwrap(); |
700 | | let mtime = FileTime::from_last_modification_time(&metadata); |
701 | | assert_eq!(mtime, new_mtime); |
702 | | |
703 | | let metadata = fs::symlink_metadata(&spath).unwrap(); |
704 | | let mtime = FileTime::from_last_modification_time(&metadata); |
705 | | assert_eq!(mtime, new_smtime); |
706 | | } |
707 | | |
708 | | #[test] |
709 | | fn set_single_time_test() { |
710 | | use super::{set_file_atime, set_file_mtime}; |
711 | | |
712 | | let td = Builder::new().prefix("filetime").tempdir().unwrap(); |
713 | | let path = td.path().join("foo.txt"); |
714 | | File::create(&path).unwrap(); |
715 | | |
716 | | let metadata = fs::metadata(&path).unwrap(); |
717 | | let mtime = FileTime::from_last_modification_time(&metadata); |
718 | | let atime = FileTime::from_last_access_time(&metadata); |
719 | | set_file_times(&path, atime, mtime).unwrap(); |
720 | | |
721 | | let new_mtime = FileTime::from_unix_time(10_000, 0); |
722 | | set_file_mtime(&path, new_mtime).unwrap(); |
723 | | |
724 | | let metadata = fs::metadata(&path).unwrap(); |
725 | | let mtime = FileTime::from_last_modification_time(&metadata); |
726 | | assert_eq!(mtime, new_mtime, "modification time should be updated"); |
727 | | assert_eq!( |
728 | | atime, |
729 | | FileTime::from_last_access_time(&metadata), |
730 | | "access time should not be updated", |
731 | | ); |
732 | | |
733 | | let new_atime = FileTime::from_unix_time(20_000, 0); |
734 | | set_file_atime(&path, new_atime).unwrap(); |
735 | | |
736 | | let metadata = fs::metadata(&path).unwrap(); |
737 | | let atime = FileTime::from_last_access_time(&metadata); |
738 | | assert_eq!(atime, new_atime, "access time should be updated"); |
739 | | assert_eq!( |
740 | | mtime, |
741 | | FileTime::from_last_modification_time(&metadata), |
742 | | "modification time should not be updated" |
743 | | ); |
744 | | } |
745 | | } |