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 = "aix", target_os = "hurd")))]
63 let nanoseconds = self.0.st_mtime_nsec;
64 #[cfg(any(target_os = "aix", target_os = "hurd"))]
65 let nanoseconds = self.0.st_mtim.tv_nsec;
66
67 let seconds = seconds as i64;
71 system_time_from_secs_nanos(seconds, nanoseconds.try_into().ok()?)
72 }
73 #[cfg(windows)]
74 self.0.modified().ok()
75 }
76
77 pub fn created(&self) -> Option<SystemTime> {
82 #[cfg(not(windows))]
83 {
84 #[cfg(not(any(target_os = "aix", target_os = "hurd")))]
85 let seconds = self.0.st_ctime;
86 #[cfg(any(target_os = "aix", target_os = "hurd"))]
87 let seconds = self.0.st_ctim.tv_sec;
88
89 #[cfg(not(any(target_os = "aix", target_os = "hurd")))]
90 let nanoseconds = self.0.st_ctime_nsec;
91 #[cfg(any(target_os = "aix", target_os = "hurd"))]
92 let nanoseconds = self.0.st_ctim.tv_nsec;
93
94 let seconds = seconds as i64;
98 system_time_from_secs_nanos(seconds, nanoseconds.try_into().ok()?)
99 }
100 #[cfg(windows)]
101 self.0.created().ok()
102 }
103
104 pub fn len(&self) -> u64 {
106 #[cfg(not(windows))]
107 {
108 self.0.st_size as u64
109 }
110 #[cfg(windows)]
111 self.0.len()
112 }
113
114 pub fn dev(&self) -> u64 {
116 #[cfg(not(windows))]
117 {
118 self.0.st_dev as u64
119 }
120 #[cfg(windows)]
121 0
122 }
123
124 pub fn ino(&self) -> u64 {
126 #[cfg(not(windows))]
127 {
128 self.0.st_ino as u64
129 }
130 #[cfg(windows)]
131 0
132 }
133
134 pub fn uid(&self) -> u32 {
136 #[cfg(not(windows))]
137 {
138 self.0.st_uid as u32
139 }
140 #[cfg(windows)]
141 0
142 }
143
144 pub fn gid(&self) -> u32 {
146 #[cfg(not(windows))]
147 {
148 self.0.st_gid as u32
149 }
150 #[cfg(windows)]
151 0
152 }
153
154 pub fn is_executable(&self) -> bool {
156 #[cfg(not(windows))]
157 {
158 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFREG as u32
159 && self.0.st_mode as u32 & libc::S_IXUSR as u32 == libc::S_IXUSR as u32
160 }
161 #[cfg(windows)]
162 gix_fs::is_executable(&self.0)
163 }
164
165 pub fn is_symlink(&self) -> bool {
167 #[cfg(not(windows))]
168 {
169 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFLNK as u32
170 }
171 #[cfg(windows)]
172 self.0.is_symlink()
173 }
174
175 pub fn is_file(&self) -> bool {
177 #[cfg(not(windows))]
178 {
179 (self.0.st_mode as u32 & libc::S_IFMT as u32) == libc::S_IFREG as u32
180 }
181 #[cfg(windows)]
182 self.0.is_file()
183 }
184}
185
186#[cfg(not(windows))]
187fn system_time_from_secs_nanos(secs: i64, nanos: i32) -> Option<SystemTime> {
188 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
202 let (secs, nanos) = if (secs <= 0 && secs > i64::MIN) && (nanos < 0 && nanos > -1_000_000_000) {
203 (secs - 1, nanos + 1_000_000_000)
204 } else {
205 (secs, nanos)
206 };
207 let d = std::time::Duration::new(secs.abs_diff(0), nanos.try_into().ok()?);
208 Some(if secs < 0 {
209 std::time::UNIX_EPOCH - d
210 } else {
211 std::time::UNIX_EPOCH + d
212 })
213}