1use crate::FileTime;
2use libc::{time_t, timespec};
3use std::fs;
4use std::os::unix::prelude::*;
5
6cfg_if::cfg_if! {
7 if #[cfg(target_os = "linux")] {
8 mod utimes;
9 mod linux;
10 pub use self::linux::*;
11 } else if #[cfg(target_os = "android")] {
12 mod android;
13 pub use self::android::*;
14 } else if #[cfg(target_os = "macos")] {
15 mod utimes;
16 mod macos;
17 pub use self::macos::*;
18 } else if #[cfg(any(target_os = "aix",
19 target_os = "solaris",
20 target_os = "illumos",
21 target_os = "emscripten",
22 target_os = "freebsd",
23 target_os = "netbsd",
24 target_os = "openbsd",
25 target_os = "haiku"))] {
26 mod utimensat;
27 pub use self::utimensat::*;
28 } else {
29 mod utimes;
30 pub use self::utimes::*;
31 }
32}
33
34#[allow(dead_code)]
35fn to_timespec(ft: &Option<FileTime>) -> timespec {
36 cfg_if::cfg_if! {
37 if #[cfg(any(target_os = "macos",
38 target_os = "illumos",
39 target_os = "freebsd"))] {
40 // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
41 // https://github.com/illumos/illumos-gate/blob/master/usr/src/boot/sys/sys/stat.h#L312
42 // https://svnweb.freebsd.org/base/head/sys/sys/stat.h?view=markup#l359
43 const UTIME_OMIT: i64 = -2;
44 } else if #[cfg(target_os = "openbsd")] {
45 // https://github.com/openbsd/src/blob/master/sys/sys/stat.h#L189
46 const UTIME_OMIT: i64 = -1;
47 } else if #[cfg(target_os = "haiku")] {
48 // https://git.haiku-os.org/haiku/tree/headers/posix/sys/stat.h?#n106
49 const UTIME_OMIT: i64 = 1000000001;
50 } else if #[cfg(target_os = "aix")] {
51 // AIX hasn't disclosed system header files yet.
52 // https://github.com/golang/go/blob/master/src/cmd/vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go#L1007
53 const UTIME_OMIT: i64 = -3;
54 } else {
55 // http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/stat.h?annotate=1.68.30.1
56 // https://github.com/emscripten-core/emscripten/blob/master/system/include/libc/sys/stat.h#L71
57 const UTIME_OMIT: i64 = 1_073_741_822;
58 }
59 }
60
61 let mut ts: timespec = unsafe { std::mem::zeroed() };
62 if let &Some(ft) = ft {
63 ts.tv_sec = ft.seconds() as time_t;
64 ts.tv_nsec = ft.nanoseconds() as _;
65 } else {
66 ts.tv_sec = 0;
67 ts.tv_nsec = UTIME_OMIT as _;
68 }
69
70 ts
71}
72
73pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
74 FileTime {
75 seconds: meta.mtime(),
76 nanos: meta.mtime_nsec() as u32,
77 }
78}
79
80pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
81 FileTime {
82 seconds: meta.atime(),
83 nanos: meta.atime_nsec() as u32,
84 }
85}
86
87pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
88 macro_rules! birthtim {
89 ($(($e:expr, $i:ident)),*) => {
90 #[cfg(any($(target_os = $e),*))]
91 fn imp(meta: &fs::Metadata) -> Option<FileTime> {
92 $(
93 #[cfg(target_os = $e)]
94 use std::os::$i::fs::MetadataExt;
95 )*
96 Some(FileTime {
97 seconds: meta.st_birthtime(),
98 nanos: meta.st_birthtime_nsec() as u32,
99 })
100 }
101
102 #[cfg(all($(not(target_os = $e)),*))]
103 fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
104 None
105 }
106 }
107 }
108
109 birthtim! {
110 ("bitrig", bitrig),
111 ("freebsd", freebsd),
112 ("ios", ios),
113 ("macos", macos),
114 ("openbsd", openbsd)
115 }
116
117 imp(meta)
118}
119