1 //! Get filesystem statistics
2 //!
3 //! See [the man pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
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 {Result, NixPath};
11 use errno::Errno;
12 
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 ///
57 /// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
58 // FIXME: Replace with repr(transparent)
59 #[repr(C)]
60 #[derive(Clone, Copy)]
61 #[allow(missing_debug_implementations)]
62 pub struct Statvfs(libc::statvfs);
63 
64 impl Statvfs {
65     /// get the file system block size
block_size(&self) -> c_ulong66     pub fn block_size(&self) -> c_ulong {
67         self.0.f_bsize
68     }
69 
70     /// Get the fundamental file system block size
fragment_size(&self) -> c_ulong71     pub fn fragment_size(&self) -> c_ulong {
72         self.0.f_frsize
73     }
74 
75     /// Get the number of blocks.
76     ///
77     /// Units are in units of `fragment_size()`
blocks(&self) -> libc::fsblkcnt_t78     pub fn blocks(&self) -> libc::fsblkcnt_t {
79         self.0.f_blocks
80     }
81 
82     /// Get the number of free blocks in the file system
blocks_free(&self) -> libc::fsblkcnt_t83     pub fn blocks_free(&self) -> libc::fsblkcnt_t {
84         self.0.f_bfree
85     }
86 
87     /// Get the number of free blocks for unprivileged users
blocks_available(&self) -> libc::fsblkcnt_t88     pub fn blocks_available(&self) -> libc::fsblkcnt_t {
89         self.0.f_bavail
90     }
91 
92     /// Get the total number of file inodes
files(&self) -> libc::fsfilcnt_t93     pub fn files(&self) -> libc::fsfilcnt_t {
94         self.0.f_files
95     }
96 
97     /// Get the number of free file inodes
files_free(&self) -> libc::fsfilcnt_t98     pub fn files_free(&self) -> libc::fsfilcnt_t {
99         self.0.f_ffree
100     }
101 
102     /// Get the number of free file inodes for unprivileged users
files_available(&self) -> libc::fsfilcnt_t103     pub fn files_available(&self) -> libc::fsfilcnt_t {
104         self.0.f_favail
105     }
106 
107     /// Get the file system id
filesystem_id(&self) -> c_ulong108     pub fn filesystem_id(&self) -> c_ulong {
109         self.0.f_fsid
110     }
111 
112     /// Get the mount flags
flags(&self) -> FsFlags113     pub fn flags(&self) -> FsFlags {
114         FsFlags::from_bits_truncate(self.0.f_flag)
115     }
116 
117     /// Get the maximum filename length
name_max(&self) -> c_ulong118     pub fn name_max(&self) -> c_ulong {
119         self.0.f_namemax
120     }
121 
122 }
123 
124 /// Return a `Statvfs` object with information about the `path`
statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs>125 pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
126     unsafe {
127         Errno::clear();
128         let mut stat: Statvfs = mem::uninitialized();
129         let res = path.with_nix_path(|path|
130             libc::statvfs(path.as_ptr(), &mut stat.0)
131         )?;
132 
133         Errno::result(res).map(|_| stat)
134     }
135 }
136 
137 /// Return a `Statvfs` object with information about `fd`
fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs>138 pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
139     unsafe {
140         Errno::clear();
141         let mut stat: Statvfs = mem::uninitialized();
142         Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
143     }
144 }
145 
146 #[cfg(test)]
147 mod test {
148     use std::fs::File;
149     use sys::statvfs::*;
150 
151     #[test]
statvfs_call()152     fn statvfs_call() {
153         statvfs("/".as_bytes()).unwrap();
154     }
155 
156     #[test]
fstatvfs_call()157     fn fstatvfs_call() {
158         let root = File::open("/").unwrap();
159         fstatvfs(&root).unwrap();
160     }
161 }
162