1//! Get filesystem statistics 2//! 3//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) 4//! for more details. 5use std::mem; 6use std::os::unix::io::AsRawFd; 7 8use libc::{self, c_ulong}; 9 10use crate::{errno::Errno, NixPath, Result}; 11 12#[cfg(not(target_os = "redox"))] 13libc_bitflags!( 14 /// File system mount Flags 15 #[repr(C)] 16 #[derive(Default)] 17 pub struct FsFlags: c_ulong { 18 /// Read Only 19 #[cfg(not(target_os = "haiku"))] 20 ST_RDONLY; 21 /// Do not allow the set-uid bits to have an effect 22 #[cfg(not(target_os = "haiku"))] 23 ST_NOSUID; 24 /// Do not interpret character or block-special devices 25 #[cfg(any(target_os = "android", target_os = "linux"))] 26 #[cfg_attr(docsrs, doc(cfg(all())))] 27 ST_NODEV; 28 /// Do not allow execution of binaries on the filesystem 29 #[cfg(any(target_os = "android", target_os = "linux"))] 30 #[cfg_attr(docsrs, doc(cfg(all())))] 31 ST_NOEXEC; 32 /// All IO should be done synchronously 33 #[cfg(any(target_os = "android", target_os = "linux"))] 34 #[cfg_attr(docsrs, doc(cfg(all())))] 35 ST_SYNCHRONOUS; 36 /// Allow mandatory locks on the filesystem 37 #[cfg(any(target_os = "android", target_os = "linux"))] 38 #[cfg_attr(docsrs, doc(cfg(all())))] 39 ST_MANDLOCK; 40 /// Write on file/directory/symlink 41 #[cfg(target_os = "linux")] 42 #[cfg_attr(docsrs, doc(cfg(all())))] 43 ST_WRITE; 44 /// Append-only file 45 #[cfg(target_os = "linux")] 46 #[cfg_attr(docsrs, doc(cfg(all())))] 47 ST_APPEND; 48 /// Immutable file 49 #[cfg(target_os = "linux")] 50 #[cfg_attr(docsrs, doc(cfg(all())))] 51 ST_IMMUTABLE; 52 /// Do not update access times on files 53 #[cfg(any(target_os = "android", target_os = "linux"))] 54 #[cfg_attr(docsrs, doc(cfg(all())))] 55 ST_NOATIME; 56 /// Do not update access times on files 57 #[cfg(any(target_os = "android", target_os = "linux"))] 58 #[cfg_attr(docsrs, doc(cfg(all())))] 59 ST_NODIRATIME; 60 /// Update access time relative to modify/change time 61 #[cfg(any(target_os = "android", all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos")))))] 62 #[cfg_attr(docsrs, doc(cfg(all())))] 63 ST_RELATIME; 64 } 65); 66 67/// Wrapper around the POSIX `statvfs` struct 68/// 69/// For more information see the [`statvfs(3)` man pages](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html). 70#[repr(transparent)] 71#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 72pub struct Statvfs(libc::statvfs); 73 74impl Statvfs { 75 /// get the file system block size 76 pub fn block_size(&self) -> c_ulong { 77 self.0.f_bsize 78 } 79 80 /// Get the fundamental file system block size 81 pub fn fragment_size(&self) -> c_ulong { 82 self.0.f_frsize 83 } 84 85 /// Get the number of blocks. 86 /// 87 /// Units are in units of `fragment_size()` 88 pub fn blocks(&self) -> libc::fsblkcnt_t { 89 self.0.f_blocks 90 } 91 92 /// Get the number of free blocks in the file system 93 pub fn blocks_free(&self) -> libc::fsblkcnt_t { 94 self.0.f_bfree 95 } 96 97 /// Get the number of free blocks for unprivileged users 98 pub fn blocks_available(&self) -> libc::fsblkcnt_t { 99 self.0.f_bavail 100 } 101 102 /// Get the total number of file inodes 103 pub fn files(&self) -> libc::fsfilcnt_t { 104 self.0.f_files 105 } 106 107 /// Get the number of free file inodes 108 pub fn files_free(&self) -> libc::fsfilcnt_t { 109 self.0.f_ffree 110 } 111 112 /// Get the number of free file inodes for unprivileged users 113 pub fn files_available(&self) -> libc::fsfilcnt_t { 114 self.0.f_favail 115 } 116 117 /// Get the file system id 118 pub fn filesystem_id(&self) -> c_ulong { 119 self.0.f_fsid 120 } 121 122 /// Get the mount flags 123 #[cfg(not(target_os = "redox"))] 124 #[cfg_attr(docsrs, doc(cfg(all())))] 125 pub fn flags(&self) -> FsFlags { 126 FsFlags::from_bits_truncate(self.0.f_flag) 127 } 128 129 /// Get the maximum filename length 130 pub fn name_max(&self) -> c_ulong { 131 self.0.f_namemax 132 } 133} 134 135/// Return a `Statvfs` object with information about the `path` 136pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> { 137 unsafe { 138 Errno::clear(); 139 let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit(); 140 let res = path.with_nix_path(|path| { 141 libc::statvfs(path.as_ptr(), stat.as_mut_ptr()) 142 })?; 143 144 Errno::result(res).map(|_| Statvfs(stat.assume_init())) 145 } 146} 147 148/// Return a `Statvfs` object with information about `fd` 149pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> { 150 unsafe { 151 Errno::clear(); 152 let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit(); 153 Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr())) 154 .map(|_| Statvfs(stat.assume_init())) 155 } 156} 157 158#[cfg(test)] 159mod test { 160 use crate::sys::statvfs::*; 161 use std::fs::File; 162 163 #[test] 164 fn statvfs_call() { 165 statvfs(&b"/"[..]).unwrap(); 166 } 167 168 #[test] 169 fn fstatvfs_call() { 170 let root = File::open("/").unwrap(); 171 fstatvfs(&root).unwrap(); 172 } 173} 174