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