Skip to main content

disk_space/
lib.rs

1use std::path::Path;
2
3#[cfg(test)]
4mod test;
5
6/// for human readability (read-only)
7pub struct DiskSpaceForHuman {
8    pub available: f64,
9    pub total: f64,
10}
11
12/// core struct
13pub struct DiskSpace {
14    pub available: u64,
15    pub total: u64,
16}
17
18impl DiskSpace {
19    /// new
20    pub fn new(path: &Path) -> Result<DiskSpace, std::io::Error> {
21        #[cfg(not(windows))]
22        {
23            use std::ffi::CString;
24
25            let c_path = CString::new(path.to_str().unwrap()).unwrap();
26            let mut stat = unsafe { std::mem::zeroed::<libc::statvfs>() };
27            let ret = unsafe { libc::statvfs(c_path.as_ptr(), &mut stat) };
28            if ret != 0 {
29                return Err(std::io::Error::last_os_error());
30            }
31            Ok(DiskSpace {
32                available: stat.f_bavail as u64 * stat.f_frsize as u64,
33                total: stat.f_blocks as u64 * stat.f_frsize as u64,
34            })
35        }
36
37        #[cfg(windows)]
38        {
39            use std::os::windows::ffi::OsStrExt;
40            let wide: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
41            let (mut free, mut total, mut tf) = (0u64, 0u64, 0u64);
42
43            #[link(name = "kernel32")]
44            unsafe extern "system" {
45                fn GetDiskFreeSpaceExW(
46                    path: *const u16,
47                    free: *mut u64,
48                    total: *mut u64,
49                    total_free: *mut u64,
50                ) -> i32;
51            }
52            let ok = unsafe { GetDiskFreeSpaceExW(wide.as_ptr(), &mut free, &mut total, &mut tf) };
53
54            if ok == 0 {
55                return Err(std::io::Error::last_os_error());
56            }
57            Ok(DiskSpace {
58                available: free,
59                total,
60            })
61        }
62    }
63
64    /// info as Megabyte
65    pub fn as_mb(&self) -> DiskSpaceForHuman {
66        let divisor = 1024u64.pow(2) as f64;
67        let (available, total) = (self.available as f64 / divisor, self.total as f64 / divisor);
68        DiskSpaceForHuman { available, total }
69    }
70
71    /// info as Gigabyte
72    pub fn as_gb(&self) -> DiskSpaceForHuman {
73        let divisor = 1024u64.pow(3) as f64;
74        let (available, total) = (self.available as f64 / divisor, self.total as f64 / divisor);
75        DiskSpaceForHuman { available, total }
76    }
77}