pavao/smb/types/
stat.rs

1//! # Stat
2//!
3//! file stat type
4#![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
15/// DOS Attribute mask for DIRECTORY
16const FILE_ATTRIBUTE_DIRECTORY: u16 = 0x0010;
17
18/// Smb statvfs type
19#[derive(Debug, Clone)]
20pub struct SmbStatVfs {
21    /// File system block size
22    pub bsize: u64,
23    /// Fragment size
24    pub frsize: u64,
25    /// Size of fs in f_frsize units
26    pub blocks: u64,
27    /// Number of free blocks
28    pub bfree: u64,
29    /// Number of free blocks for unprivileged users
30    pub bavail: u64,
31    /// Number of inodes
32    pub files: u64,
33    /// Number of free inodes
34    pub ffree: u64,
35    /// Number of free inodes for unprivileged users
36    pub favail: u64,
37    /// Filesystem ID
38    pub fsid: u64,
39    /// Mount flags
40    pub flag: u64,
41    /// Maximum filename length
42    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/// Smb stat type
142#[derive(Debug, Clone)]
143pub struct SmbStat {
144    /// Last access time
145    pub accessed: SystemTime,
146    /// Blocks occupied by file
147    pub blocks: i64,
148    /// Block size
149    pub blksize: i64,
150    /// Creation time
151    pub created: SystemTime,
152    /// Device
153    pub dev: i32,
154    /// Group id
155    pub gid: u32,
156    /// Unix permissions
157    pub mode: SmbMode,
158    /// Modify time
159    pub modified: SystemTime,
160    /// Link associated to file
161    pub nlink: u64,
162    pub rdev: u64,
163    /// File size in bytes
164    pub size: u64,
165    /// User id
166    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/// SMB directory entity with metadata
241#[derive(Debug, Clone)]
242pub struct SmbDirentInfo {
243    /// Name of file
244    pub name: String,
245    /// Short name of file
246    pub short_name: String,
247    /// Size of file
248    pub size: u64,
249    /// DOS attributes of file
250    pub attrs: u16,
251    /// Change time for the file
252    pub ctime: SystemTime,
253    /// Birth/Create time of file (if not supported, it will be 0)
254    pub btime: SystemTime,
255    /// Modified time for the file
256    pub mtime: SystemTime,
257    /// Access time for the file
258    pub atime: SystemTime,
259    /// Group ID of file
260    pub uid: u32,
261    /// User ID of file
262    pub gid: u32,
263}
264
265impl SmbDirentInfo {
266    /// Get directory entity type
267    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    /// Get name
276    pub fn name(&self) -> &str {
277        self.name.as_str()
278    }
279
280    /// Get short name
281    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}