Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}