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::{AsFd, AsRawFd};
78use libc::{self, c_ulong};
910use crate::{errno::Errno, NixPath, Result};
1112#[cfg(not(target_os = "redox"))]
13libc_bitflags!(
14/// File system mount Flags
15#[derive(Default)]
16pub struct FsFlags: c_ulong {
17/// Read Only
18#[cfg(not(target_os = "haiku"))]
19ST_RDONLY;
20/// Do not allow the set-uid bits to have an effect
21#[cfg(not(target_os = "haiku"))]
22ST_NOSUID;
23/// Do not interpret character or block-special devices
24#[cfg(linux_android)]
25ST_NODEV;
26/// Do not allow execution of binaries on the filesystem
27#[cfg(linux_android)]
28ST_NOEXEC;
29/// All IO should be done synchronously
30#[cfg(linux_android)]
31ST_SYNCHRONOUS;
32/// Allow mandatory locks on the filesystem
33#[cfg(linux_android)]
34ST_MANDLOCK;
35/// Write on file/directory/symlink
36#[cfg(target_os = "linux")]
37ST_WRITE;
38/// Append-only file
39#[cfg(target_os = "linux")]
40ST_APPEND;
41/// Immutable file
42#[cfg(target_os = "linux")]
43ST_IMMUTABLE;
44/// Do not update access times on files
45#[cfg(linux_android)]
46ST_NOATIME;
47/// Do not update access times on files
48#[cfg(linux_android)]
49ST_NODIRATIME;
50/// Update access time relative to modify/change time
51#[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos"))))]
52ST_RELATIME;
53 }
54);
5556/// Wrapper around the POSIX `statvfs` struct
57///
58/// For more information see the [`statvfs(3)` man pages](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
59#[repr(transparent)]
60#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
61pub struct Statvfs(libc::statvfs);
6263impl Statvfs {
64/// get the file system block size
65pub fn block_size(&self) -> c_ulong {
66self.0.f_bsize
67 }
6869/// Get the fundamental file system block size
70pub fn fragment_size(&self) -> c_ulong {
71self.0.f_frsize
72 }
7374/// Get the number of blocks.
75 ///
76 /// Units are in units of `fragment_size()`
77pub fn blocks(&self) -> libc::fsblkcnt_t {
78self.0.f_blocks
79 }
8081/// Get the number of free blocks in the file system
82pub fn blocks_free(&self) -> libc::fsblkcnt_t {
83self.0.f_bfree
84 }
8586/// Get the number of free blocks for unprivileged users
87pub fn blocks_available(&self) -> libc::fsblkcnt_t {
88self.0.f_bavail
89 }
9091/// Get the total number of file inodes
92pub fn files(&self) -> libc::fsfilcnt_t {
93self.0.f_files
94 }
9596/// Get the number of free file inodes
97pub fn files_free(&self) -> libc::fsfilcnt_t {
98self.0.f_ffree
99 }
100101/// Get the number of free file inodes for unprivileged users
102pub fn files_available(&self) -> libc::fsfilcnt_t {
103self.0.f_favail
104 }
105106/// Get the file system id
107#[cfg(not(target_os = "hurd"))]
108pub fn filesystem_id(&self) -> c_ulong {
109self.0.f_fsid
110 }
111/// Get the file system id
112#[cfg(target_os = "hurd")]
113pub fn filesystem_id(&self) -> u64 {
114self.0.f_fsid
115 }
116117/// Get the mount flags
118#[cfg(not(target_os = "redox"))]
119pub fn flags(&self) -> FsFlags {
120 FsFlags::from_bits_truncate(self.0.f_flag)
121 }
122123/// Get the maximum filename length
124pub fn name_max(&self) -> c_ulong {
125self.0.f_namemax
126 }
127}
128129/// Return a `Statvfs` object with information about the `path`
130pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
131unsafe {
132 Errno::clear();
133let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
134let res = path.with_nix_path(|path| {
135 libc::statvfs(path.as_ptr(), stat.as_mut_ptr())
136 })?;
137138 Errno::result(res).map(|_| Statvfs(stat.assume_init()))
139 }
140}
141142/// Return a `Statvfs` object with information about `fd`
143pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> Result<Statvfs> {
144unsafe {
145 Errno::clear();
146let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
147 Errno::result(libc::fstatvfs(fd.as_fd().as_raw_fd(), stat.as_mut_ptr()))
148 .map(|_| Statvfs(stat.assume_init()))
149 }
150}