1#![allow(clippy::unnecessary_cast)]
5
6use std::time::{Duration, SystemTime, UNIX_EPOCH};
7
8use libc::{stat, statvfs, time_t};
9use pavao_sys::libsmb_file_info;
10
11use super::SmbMode;
12use crate::utils::char_ptr_to_string;
13use crate::{SmbDirentType, SmbError};
14
15const FILE_ATTRIBUTE_DIRECTORY: u16 = 0x0010;
17
18#[derive(Debug, Clone)]
20pub struct SmbStatVfs {
21 pub bsize: u64,
23 pub frsize: u64,
25 pub blocks: u64,
27 pub bfree: u64,
29 pub bavail: u64,
31 pub files: u64,
33 pub ffree: u64,
35 pub favail: u64,
37 pub fsid: u64,
39 pub flag: u64,
41 pub namemax: u64,
43}
44
45impl From<statvfs> for SmbStatVfs {
46 fn from(s: statvfs) -> Self {
47 Self {
48 bsize: s.f_bsize as u64,
49 frsize: s.f_frsize as u64,
50 #[cfg(target_os = "android")]
51 blocks: s.f_blocks,
52 #[cfg(target_os = "macos")]
53 blocks: s.f_blocks as u64,
54 #[cfg(linux_x86_64)]
55 blocks: s.f_blocks,
56 #[cfg(linux_aarch64)]
57 blocks: s.f_blocks,
58 #[cfg(linux_arm)]
59 blocks: s.f_blocks as u64,
60 #[cfg(linux_riscv64)]
61 blocks: s.f_blocks,
62 #[cfg(target_os = "openbsd")]
63 blocks: s.f_blocks,
64 #[cfg(target_os = "android")]
65 bfree: s.f_bfree,
66 #[cfg(target_os = "macos")]
67 bfree: s.f_bfree as u64,
68 #[cfg(linux_x86_64)]
69 bfree: s.f_bfree,
70 #[cfg(linux_aarch64)]
71 bfree: s.f_bfree,
72 #[cfg(linux_arm)]
73 bfree: s.f_bfree as u64,
74 #[cfg(linux_riscv64)]
75 bfree: s.f_bfree,
76 #[cfg(target_os = "openbsd")]
77 bfree: s.f_bfree,
78 #[cfg(target_os = "android")]
79 bavail: s.f_bavail,
80 #[cfg(target_os = "macos")]
81 bavail: s.f_bavail as u64,
82 #[cfg(linux_x86_64)]
83 bavail: s.f_bavail,
84 #[cfg(linux_aarch64)]
85 bavail: s.f_bavail,
86 #[cfg(linux_arm)]
87 bavail: s.f_bavail as u64,
88 #[cfg(linux_riscv64)]
89 bavail: s.f_bavail,
90 #[cfg(target_os = "openbsd")]
91 bavail: s.f_bavail,
92 #[cfg(target_os = "android")]
93 files: s.f_files,
94 #[cfg(target_os = "macos")]
95 files: s.f_files as u64,
96 #[cfg(linux_x86_64)]
97 files: s.f_files,
98 #[cfg(linux_aarch64)]
99 files: s.f_files,
100 #[cfg(linux_arm)]
101 files: s.f_files as u64,
102 #[cfg(linux_riscv64)]
103 files: s.f_files,
104 #[cfg(target_os = "openbsd")]
105 files: s.f_files,
106 #[cfg(target_os = "android")]
107 ffree: s.f_ffree,
108 #[cfg(target_os = "macos")]
109 ffree: s.f_ffree as u64,
110 #[cfg(linux_x86_64)]
111 ffree: s.f_ffree,
112 #[cfg(linux_aarch64)]
113 ffree: s.f_ffree,
114 #[cfg(linux_arm)]
115 ffree: s.f_ffree as u64,
116 #[cfg(linux_riscv64)]
117 ffree: s.f_ffree,
118 #[cfg(target_os = "openbsd")]
119 ffree: s.f_ffree,
120 #[cfg(target_os = "android")]
121 favail: s.f_favail,
122 #[cfg(target_os = "macos")]
123 favail: s.f_favail as u64,
124 #[cfg(linux_x86_64)]
125 favail: s.f_favail,
126 #[cfg(linux_aarch64)]
127 favail: s.f_favail,
128 #[cfg(linux_arm)]
129 favail: s.f_favail as u64,
130 #[cfg(linux_riscv64)]
131 favail: s.f_favail,
132 #[cfg(target_os = "openbsd")]
133 favail: s.f_favail,
134 fsid: s.f_fsid as u64,
135 flag: s.f_flag as u64,
136 namemax: s.f_namemax as u64,
137 }
138 }
139}
140
141#[derive(Debug, Clone)]
143pub struct SmbStat {
144 pub accessed: SystemTime,
146 pub blocks: i64,
148 pub blksize: i64,
150 pub created: SystemTime,
152 pub dev: i32,
154 pub gid: u32,
156 pub mode: SmbMode,
158 pub modified: SystemTime,
160 pub nlink: u64,
162 pub rdev: u64,
163 pub size: u64,
165 pub uid: u32,
167}
168
169impl From<stat> for SmbStat {
170 fn from(s: stat) -> Self {
171 Self {
172 accessed: time_t_to_system_time(s.st_atime),
173 blocks: s.st_blocks as i64,
174 #[cfg(target_os = "android")]
175 blksize: s.st_blksize as i64,
176 #[cfg(target_os = "macos")]
177 blksize: s.st_blksize as i64,
178 #[cfg(linux_x86_64)]
179 blksize: s.st_blksize,
180 #[cfg(linux_aarch64)]
181 blksize: s.st_blksize as i64,
182 #[cfg(linux_arm)]
183 blksize: s.st_blksize as i64,
184 #[cfg(linux_riscv64)]
185 blksize: s.st_blksize as i64,
186 created: time_t_to_system_time(s.st_ctime),
187 #[cfg(target_os = "openbsd")]
188 blksize: s.st_blksize as i64,
189 #[cfg(target_os = "android")]
190 dev: s.st_dev as i32,
191 #[cfg(target_os = "macos")]
192 dev: s.st_dev,
193 #[cfg(linux_x86_64)]
194 dev: s.st_dev as i32,
195 #[cfg(linux_aarch64)]
196 dev: s.st_dev as i32,
197 #[cfg(linux_arm)]
198 dev: s.st_dev as i32,
199 #[cfg(linux_riscv64)]
200 dev: s.st_dev as i32,
201 gid: s.st_gid,
202 mode: SmbMode::from(s.st_mode),
203 modified: time_t_to_system_time(s.st_mtime),
204 #[cfg(target_os = "openbsd")]
205 dev: s.st_dev as i32,
206 #[cfg(target_os = "android")]
207 nlink: s.st_nlink as u64,
208 #[cfg(target_os = "macos")]
209 nlink: s.st_nlink as u64,
210 #[cfg(linux_x86_64)]
211 nlink: s.st_nlink,
212 #[cfg(linux_aarch64)]
213 nlink: s.st_nlink as u64,
214 #[cfg(linux_arm)]
215 nlink: s.st_nlink as u64,
216 #[cfg(linux_riscv64)]
217 nlink: s.st_nlink as u64,
218 #[cfg(target_os = "openbsd")]
219 nlink: s.st_nlink as u64,
220 #[cfg(target_os = "android")]
221 rdev: s.st_rdev as u64,
222 #[cfg(target_os = "macos")]
223 rdev: s.st_rdev as u64,
224 #[cfg(linux_x86_64)]
225 rdev: s.st_rdev,
226 #[cfg(linux_aarch64)]
227 rdev: s.st_rdev as u64,
228 #[cfg(linux_arm)]
229 rdev: s.st_rdev as u64,
230 #[cfg(linux_riscv64)]
231 rdev: s.st_rdev as u64,
232 #[cfg(target_os = "openbsd")]
233 rdev: s.st_rdev as u64,
234 size: s.st_size as u64,
235 uid: s.st_uid,
236 }
237 }
238}
239
240#[derive(Debug, Clone)]
242pub struct SmbDirentInfo {
243 pub name: String,
245 pub short_name: String,
247 pub size: u64,
249 pub attrs: u16,
251 pub ctime: SystemTime,
253 pub btime: SystemTime,
255 pub mtime: SystemTime,
257 pub atime: SystemTime,
259 pub uid: u32,
261 pub gid: u32,
263}
264
265impl SmbDirentInfo {
266 pub fn get_type(&self) -> SmbDirentType {
268 if self.attrs & FILE_ATTRIBUTE_DIRECTORY != 0 {
269 SmbDirentType::Dir
270 } else {
271 SmbDirentType::File
272 }
273 }
274
275 pub fn name(&self) -> &str {
277 self.name.as_str()
278 }
279
280 pub fn short_name(&self) -> &str {
282 self.short_name.as_str()
283 }
284}
285
286impl TryFrom<libsmb_file_info> for SmbDirentInfo {
287 type Error = SmbError;
288
289 fn try_from(di: libsmb_file_info) -> Result<Self, Self::Error> {
290 let name = char_ptr_to_string(di.name)?;
291 let short_name = char_ptr_to_string(di.short_name)?;
292
293 Ok(Self {
294 name,
295 short_name,
296 size: di.size as u64,
297 ctime: time_t_to_system_time(di.ctime_ts.tv_sec),
298 btime: time_t_to_system_time(di.btime_ts.tv_sec),
299 mtime: time_t_to_system_time(di.mtime_ts.tv_sec),
300 atime: time_t_to_system_time(di.atime_ts.tv_sec),
301 uid: di.uid,
302 gid: di.gid,
303 attrs: di.attrs,
304 })
305 }
306}
307
308fn time_t_to_system_time(t: time_t) -> SystemTime {
309 UNIX_EPOCH
310 .checked_add(Duration::from_secs(t as u64))
311 .unwrap_or(UNIX_EPOCH)
312}
313
314#[cfg(test)]
315mod test {
316
317 use pretty_assertions::assert_ne;
318
319 use super::*;
320
321 #[test]
322 fn should_convert_time_t_into_system_time() {
323 assert_ne!(time_t_to_system_time(1000), UNIX_EPOCH);
324 }
325}