1#![allow(clippy::useless_conversion)] #![allow(clippy::unnecessary_cast)]
5
6use std::{path::Path, time::SystemTime};
8
9#[cfg(not(windows))]
11pub struct Metadata(rustix::fs::Stat);
12
13#[cfg(windows)]
14pub struct Metadata(std::fs::Metadata);
16
17impl Metadata {
19 pub fn from_path_no_follow(path: &Path) -> Result<Self, std::io::Error> {
21 #[cfg(not(windows))]
22 {
23 rustix::fs::lstat(path).map(Metadata).map_err(Into::into)
24 }
25 #[cfg(windows)]
26 path.symlink_metadata().map(Metadata)
27 }
28
29 pub fn from_file(file: &std::fs::File) -> Result<Self, std::io::Error> {
31 #[cfg(not(windows))]
32 {
33 rustix::fs::fstat(file).map(Metadata).map_err(Into::into)
34 }
35 #[cfg(windows)]
36 file.metadata().map(Metadata)
37 }
38}
39
40#[allow(clippy::len_without_is_empty)]
42impl Metadata {
43 pub fn is_dir(&self) -> bool {
45 #[cfg(not(windows))]
46 {
47 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFDIR as u32
48 }
49 #[cfg(windows)]
50 self.0.is_dir()
51 }
52
53 pub fn modified(&self) -> Option<SystemTime> {
55 #[cfg(not(windows))]
56 {
57 #[cfg(not(any(target_os = "aix", target_os = "hurd")))]
58 let seconds = self.0.st_mtime;
59 #[cfg(any(target_os = "aix", target_os = "hurd"))]
60 let seconds = self.0.st_mtim.tv_sec;
61
62 #[cfg(not(any(target_os = "netbsd", target_os = "aix", target_os = "hurd")))]
63 let nanoseconds = self.0.st_mtime_nsec;
64 #[cfg(target_os = "netbsd")]
65 let nanoseconds = self.0.st_mtimensec;
66 #[cfg(any(target_os = "aix", target_os = "hurd"))]
67 let nanoseconds = self.0.st_mtim.tv_nsec;
68
69 let seconds = seconds as i64;
73 system_time_from_secs_nanos(seconds, nanoseconds.try_into().ok()?)
74 }
75 #[cfg(windows)]
76 self.0.modified().ok()
77 }
78
79 pub fn created(&self) -> Option<SystemTime> {
84 #[cfg(not(windows))]
85 {
86 #[cfg(not(any(target_os = "aix", target_os = "hurd")))]
87 let seconds = self.0.st_ctime;
88 #[cfg(any(target_os = "aix", target_os = "hurd"))]
89 let seconds = self.0.st_ctim.tv_sec;
90
91 #[cfg(not(any(target_os = "netbsd", target_os = "aix", target_os = "hurd")))]
92 let nanoseconds = self.0.st_ctime_nsec;
93 #[cfg(target_os = "netbsd")]
94 let nanoseconds = self.0.st_ctimensec;
95 #[cfg(any(target_os = "aix", target_os = "hurd"))]
96 let nanoseconds = self.0.st_ctim.tv_nsec;
97
98 let seconds = seconds as i64;
102 system_time_from_secs_nanos(seconds, nanoseconds.try_into().ok()?)
103 }
104 #[cfg(windows)]
105 self.0.created().ok()
106 }
107
108 pub fn len(&self) -> u64 {
110 #[cfg(not(windows))]
111 {
112 self.0.st_size as u64
113 }
114 #[cfg(windows)]
115 self.0.len()
116 }
117
118 pub fn dev(&self) -> u64 {
120 #[cfg(not(windows))]
121 {
122 self.0.st_dev as u64
123 }
124 #[cfg(windows)]
125 0
126 }
127
128 pub fn ino(&self) -> u64 {
130 #[cfg(not(windows))]
131 {
132 self.0.st_ino as u64
133 }
134 #[cfg(windows)]
135 0
136 }
137
138 pub fn uid(&self) -> u32 {
140 #[cfg(not(windows))]
141 {
142 self.0.st_uid as u32
143 }
144 #[cfg(windows)]
145 0
146 }
147
148 pub fn gid(&self) -> u32 {
150 #[cfg(not(windows))]
151 {
152 self.0.st_gid as u32
153 }
154 #[cfg(windows)]
155 0
156 }
157
158 pub fn is_executable(&self) -> bool {
160 #[cfg(not(windows))]
161 {
162 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFREG as u32
163 && self.0.st_mode as u32 & libc::S_IXUSR as u32 == libc::S_IXUSR as u32
164 }
165 #[cfg(windows)]
166 gix_fs::is_executable(&self.0)
167 }
168
169 pub fn is_symlink(&self) -> bool {
171 #[cfg(not(windows))]
172 {
173 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFLNK as u32
174 }
175 #[cfg(windows)]
176 self.0.is_symlink()
177 }
178
179 pub fn is_file(&self) -> bool {
181 #[cfg(not(windows))]
182 {
183 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFREG as u32
184 }
185 #[cfg(windows)]
186 self.0.is_file()
187 }
188}
189
190#[cfg(not(windows))]
191fn system_time_from_secs_nanos(secs: i64, nanos: i32) -> Option<SystemTime> {
192 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
206 let (secs, nanos) = if (secs <= 0 && secs > i64::MIN) && (nanos < 0 && nanos > -1_000_000_000) {
207 (secs - 1, nanos + 1_000_000_000)
208 } else {
209 (secs, nanos)
210 };
211 let d = std::time::Duration::new(secs.abs_diff(0), nanos.try_into().ok()?);
212 Some(if secs < 0 {
213 std::time::UNIX_EPOCH - d
214 } else {
215 std::time::UNIX_EPOCH + d
216 })
217}