nix/sys/
statfs.rs

1//! Get filesystem statistics, non-portably
2//!
3//! See [`statvfs`](crate::sys::statvfs) for a portable alternative.
4use std::fmt::{self, Debug};
5use std::mem;
6use std::os::unix::io::AsRawFd;
7#[cfg(not(any(target_os = "linux", target_os = "android")))]
8use std::ffi::CStr;
9
10use crate::{NixPath, Result, errno::Errno};
11
12/// Identifies a mounted file system
13#[cfg(target_os = "android")]
14#[cfg_attr(docsrs, doc(cfg(all())))]
15pub type fsid_t = libc::__fsid_t;
16/// Identifies a mounted file system
17#[cfg(not(target_os = "android"))]
18#[cfg_attr(docsrs, doc(cfg(all())))]
19pub type fsid_t = libc::fsid_t;
20
21/// Describes a mounted file system
22#[derive(Clone, Copy)]
23#[repr(transparent)]
24pub struct Statfs(libc::statfs);
25
26#[cfg(target_os = "freebsd")]
27type fs_type_t = u32;
28#[cfg(target_os = "android")]
29type fs_type_t = libc::c_ulong;
30#[cfg(all(target_os = "linux", target_arch = "s390x"))]
31type fs_type_t = libc::c_uint;
32#[cfg(all(target_os = "linux", target_env = "musl"))]
33type fs_type_t = libc::c_ulong;
34#[cfg(all(target_os = "linux", target_env = "uclibc"))]
35type fs_type_t = libc::c_int;
36#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))]
37type fs_type_t = libc::__fsword_t;
38
39/// Describes the file system type as known by the operating system.
40#[cfg(any(
41    target_os = "freebsd",
42    target_os = "android",
43    all(target_os = "linux", target_arch = "s390x"),
44    all(target_os = "linux", target_env = "musl"),
45    all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))),
46))]
47#[derive(Eq, Copy, Clone, PartialEq, Debug)]
48pub struct FsType(pub fs_type_t);
49
50// These constants are defined without documentation in the Linux headers, so we
51// can't very well document them here.
52#[cfg(any(target_os = "linux", target_os = "android"))]
53#[allow(missing_docs)]
54pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
55#[cfg(any(target_os = "linux", target_os = "android"))]
56#[allow(missing_docs)]
57pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
58#[cfg(any(target_os = "linux", target_os = "android"))]
59#[allow(missing_docs)]
60pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t);
61#[cfg(any(target_os = "linux", target_os = "android"))]
62#[allow(missing_docs)]
63pub const AUTOFS_SUPER_MAGIC: FsType = FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t);
64#[cfg(any(target_os = "linux", target_os = "android"))]
65#[allow(missing_docs)]
66pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t);
67#[cfg(any(target_os = "linux", target_os = "android"))]
68#[allow(missing_docs)]
69pub const BTRFS_SUPER_MAGIC: FsType = FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t);
70#[cfg(any(target_os = "linux", target_os = "android"))]
71#[allow(missing_docs)]
72pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
73#[cfg(any(target_os = "linux", target_os = "android"))]
74#[allow(missing_docs)]
75pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
76#[cfg(any(target_os = "linux", target_os = "android"))]
77#[allow(missing_docs)]
78pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
79#[cfg(any(target_os = "linux", target_os = "android"))]
80#[allow(missing_docs)]
81pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
82#[cfg(any(target_os = "linux", target_os = "android"))]
83#[allow(missing_docs)]
84pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t);
85#[cfg(any(target_os = "linux", target_os = "android"))]
86#[allow(missing_docs)]
87pub const DEVPTS_SUPER_MAGIC: FsType = FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t);
88#[cfg(any(target_os = "linux", target_os = "android"))]
89#[allow(missing_docs)]
90pub const ECRYPTFS_SUPER_MAGIC: FsType = FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t);
91#[cfg(any(target_os = "linux", target_os = "android"))]
92#[allow(missing_docs)]
93pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t);
94#[cfg(any(target_os = "linux", target_os = "android"))]
95#[allow(missing_docs)]
96pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
97#[cfg(any(target_os = "linux", target_os = "android"))]
98#[allow(missing_docs)]
99pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
100#[cfg(any(target_os = "linux", target_os = "android"))]
101#[allow(missing_docs)]
102pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
103#[cfg(any(target_os = "linux", target_os = "android"))]
104#[allow(missing_docs)]
105pub const F2FS_SUPER_MAGIC: FsType = FsType(libc::F2FS_SUPER_MAGIC as fs_type_t);
106#[cfg(any(target_os = "linux", target_os = "android"))]
107#[allow(missing_docs)]
108pub const FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_SUPER_MAGIC as fs_type_t);
109#[cfg(any(target_os = "linux", target_os = "android"))]
110#[allow(missing_docs)]
111pub const FUTEXFS_SUPER_MAGIC: FsType = FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t);
112#[cfg(any(target_os = "linux", target_os = "android"))]
113#[allow(missing_docs)]
114pub const HOSTFS_SUPER_MAGIC: FsType = FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t);
115#[cfg(any(target_os = "linux", target_os = "android"))]
116#[allow(missing_docs)]
117pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
118#[cfg(any(target_os = "linux", target_os = "android"))]
119#[allow(missing_docs)]
120pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t);
121#[cfg(any(target_os = "linux", target_os = "android"))]
122#[allow(missing_docs)]
123pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
124#[cfg(any(target_os = "linux", target_os = "android"))]
125#[allow(missing_docs)]
126pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
127#[cfg(any(target_os = "linux", target_os = "android"))]
128#[allow(missing_docs)]
129pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
130#[cfg(any(target_os = "linux", target_os = "android"))]
131#[allow(missing_docs)]
132pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
133#[cfg(any(target_os = "linux", target_os = "android"))]
134#[allow(missing_docs)]
135pub const MINIX3_SUPER_MAGIC: FsType = FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t);
136#[cfg(any(target_os = "linux", target_os = "android"))]
137#[allow(missing_docs)]
138pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
139#[cfg(any(target_os = "linux", target_os = "android"))]
140#[allow(missing_docs)]
141pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
142#[cfg(any(target_os = "linux", target_os = "android"))]
143#[allow(missing_docs)]
144pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
145#[cfg(any(target_os = "linux", target_os = "android"))]
146#[allow(missing_docs)]
147pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
148#[cfg(any(target_os = "linux", target_os = "android"))]
149#[allow(missing_docs)]
150pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
151#[cfg(any(target_os = "linux", target_os = "android"))]
152#[allow(missing_docs)]
153pub const NILFS_SUPER_MAGIC: FsType = FsType(libc::NILFS_SUPER_MAGIC as fs_type_t);
154#[cfg(any(target_os = "linux", target_os = "android"))]
155#[allow(missing_docs)]
156pub const OCFS2_SUPER_MAGIC: FsType = FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t);
157#[cfg(any(target_os = "linux", target_os = "android"))]
158#[allow(missing_docs)]
159pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
160#[cfg(any(target_os = "linux", target_os = "android"))]
161#[allow(missing_docs)]
162pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
163#[cfg(any(target_os = "linux", target_os = "android"))]
164#[allow(missing_docs)]
165pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
166#[cfg(any(target_os = "linux", target_os = "android"))]
167#[allow(missing_docs)]
168pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
169#[cfg(any(target_os = "linux", target_os = "android"))]
170#[allow(missing_docs)]
171pub const QNX6_SUPER_MAGIC: FsType = FsType(libc::QNX6_SUPER_MAGIC as fs_type_t);
172#[cfg(any(target_os = "linux", target_os = "android"))]
173#[allow(missing_docs)]
174pub const RDTGROUP_SUPER_MAGIC: FsType = FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t);
175#[cfg(any(target_os = "linux", target_os = "android"))]
176#[allow(missing_docs)]
177pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
178#[cfg(any(target_os = "linux", target_os = "android"))]
179#[allow(missing_docs)]
180pub const SECURITYFS_MAGIC: FsType = FsType(libc::SECURITYFS_MAGIC as fs_type_t);
181#[cfg(any(target_os = "linux", target_os = "android"))]
182#[allow(missing_docs)]
183pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t);
184#[cfg(any(target_os = "linux", target_os = "android"))]
185#[allow(missing_docs)]
186pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t);
187#[cfg(any(target_os = "linux", target_os = "android"))]
188#[allow(missing_docs)]
189pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
190#[cfg(any(target_os = "linux", target_os = "android"))]
191#[allow(missing_docs)]
192pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t);
193#[cfg(any(target_os = "linux", target_os = "android"))]
194#[allow(missing_docs)]
195pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
196#[cfg(any(target_os = "linux", target_os = "android"))]
197#[allow(missing_docs)]
198pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t);
199#[cfg(any(target_os = "linux", target_os = "android"))]
200#[allow(missing_docs)]
201pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t);
202#[cfg(any(target_os = "linux", target_os = "android"))]
203#[allow(missing_docs)]
204pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
205#[cfg(any(target_os = "linux", target_os = "android"))]
206#[allow(missing_docs)]
207pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_t);
208
209
210impl Statfs {
211    /// Magic code defining system type
212    #[cfg(not(any(
213        target_os = "openbsd",
214        target_os = "dragonfly",
215        target_os = "ios",
216        target_os = "macos"
217    )))]
218    #[cfg_attr(docsrs, doc(cfg(all())))]
219    pub fn filesystem_type(&self) -> FsType {
220        FsType(self.0.f_type)
221    }
222
223    /// Magic code defining system type
224    #[cfg(not(any(target_os = "linux", target_os = "android")))]
225    #[cfg_attr(docsrs, doc(cfg(all())))]
226    pub fn filesystem_type_name(&self) -> &str {
227        let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
228        c_str.to_str().unwrap()
229    }
230
231    /// Optimal transfer block size
232    #[cfg(any(target_os = "ios", target_os = "macos"))]
233    #[cfg_attr(docsrs, doc(cfg(all())))]
234    pub fn optimal_transfer_size(&self) -> i32 {
235        self.0.f_iosize
236    }
237
238    /// Optimal transfer block size
239    #[cfg(target_os = "openbsd")]
240    #[cfg_attr(docsrs, doc(cfg(all())))]
241    pub fn optimal_transfer_size(&self) -> u32 {
242        self.0.f_iosize
243    }
244
245    /// Optimal transfer block size
246    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
247    #[cfg_attr(docsrs, doc(cfg(all())))]
248    pub fn optimal_transfer_size(&self) -> u32 {
249        self.0.f_bsize
250    }
251
252    /// Optimal transfer block size
253    #[cfg(any(
254        target_os = "android",
255        all(target_os = "linux", target_env = "musl")
256    ))]
257    #[cfg_attr(docsrs, doc(cfg(all())))]
258    pub fn optimal_transfer_size(&self) -> libc::c_ulong {
259        self.0.f_bsize
260    }
261
262    /// Optimal transfer block size
263    #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))]
264    #[cfg_attr(docsrs, doc(cfg(all())))]
265    pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
266        self.0.f_bsize
267    }
268
269    /// Optimal transfer block size
270    #[cfg(all(target_os = "linux", target_env = "uclibc"))]
271    #[cfg_attr(docsrs, doc(cfg(all())))]
272    pub fn optimal_transfer_size(&self) -> libc::c_int {
273        self.0.f_bsize
274    }
275
276    /// Optimal transfer block size
277    #[cfg(target_os = "dragonfly")]
278    #[cfg_attr(docsrs, doc(cfg(all())))]
279    pub fn optimal_transfer_size(&self) -> libc::c_long {
280        self.0.f_iosize
281    }
282
283    /// Optimal transfer block size
284    #[cfg(target_os = "freebsd")]
285    #[cfg_attr(docsrs, doc(cfg(all())))]
286    pub fn optimal_transfer_size(&self) -> u64 {
287        self.0.f_iosize
288    }
289
290    /// Size of a block
291    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
292    #[cfg_attr(docsrs, doc(cfg(all())))]
293    pub fn block_size(&self) -> u32 {
294        self.0.f_bsize
295    }
296
297    /// Size of a block
298    // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
299    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
300    #[cfg_attr(docsrs, doc(cfg(all())))]
301    pub fn block_size(&self) -> u32 {
302        self.0.f_bsize
303    }
304
305    /// Size of a block
306    // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
307    #[cfg(all(target_os = "linux", target_env = "musl"))]
308    #[cfg_attr(docsrs, doc(cfg(all())))]
309    pub fn block_size(&self) -> libc::c_ulong {
310        self.0.f_bsize
311    }
312
313    /// Size of a block
314    // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
315    #[cfg(all(target_os = "linux", target_env = "uclibc"))]
316    #[cfg_attr(docsrs, doc(cfg(all())))]
317    pub fn block_size(&self) -> libc::c_int {
318        self.0.f_bsize
319    }
320
321    /// Size of a block
322    // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
323    #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))]
324    #[cfg_attr(docsrs, doc(cfg(all())))]
325    pub fn block_size(&self) -> libc::__fsword_t {
326        self.0.f_bsize
327    }
328
329    /// Size of a block
330    #[cfg(target_os = "freebsd")]
331    #[cfg_attr(docsrs, doc(cfg(all())))]
332    pub fn block_size(&self) -> u64 {
333        self.0.f_bsize
334    }
335
336    /// Size of a block
337    #[cfg(target_os = "android")]
338    #[cfg_attr(docsrs, doc(cfg(all())))]
339    pub fn block_size(&self) -> libc::c_ulong {
340        self.0.f_bsize
341    }
342
343    /// Size of a block
344    #[cfg(target_os = "dragonfly")]
345    #[cfg_attr(docsrs, doc(cfg(all())))]
346    pub fn block_size(&self) -> libc::c_long {
347        self.0.f_bsize
348    }
349
350    /// Maximum length of filenames
351    #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
352    #[cfg_attr(docsrs, doc(cfg(all())))]
353    pub fn maximum_name_length(&self) -> u32 {
354        self.0.f_namemax
355    }
356
357    /// Maximum length of filenames
358    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
359    #[cfg_attr(docsrs, doc(cfg(all())))]
360    pub fn maximum_name_length(&self) -> u32 {
361        self.0.f_namelen
362    }
363
364    /// Maximum length of filenames
365    #[cfg(all(target_os = "linux", target_env = "musl"))]
366    #[cfg_attr(docsrs, doc(cfg(all())))]
367    pub fn maximum_name_length(&self) -> libc::c_ulong {
368        self.0.f_namelen
369    }
370
371    /// Maximum length of filenames
372    #[cfg(all(target_os = "linux", target_env = "uclibc"))]
373    #[cfg_attr(docsrs, doc(cfg(all())))]
374    pub fn maximum_name_length(&self) -> libc::c_int {
375        self.0.f_namelen
376    }
377
378    /// Maximum length of filenames
379    #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))]
380    #[cfg_attr(docsrs, doc(cfg(all())))]
381    pub fn maximum_name_length(&self) -> libc::__fsword_t {
382        self.0.f_namelen
383    }
384
385    /// Maximum length of filenames
386    #[cfg(target_os = "android")]
387    #[cfg_attr(docsrs, doc(cfg(all())))]
388    pub fn maximum_name_length(&self) -> libc::c_ulong {
389        self.0.f_namelen
390    }
391
392    /// Total data blocks in filesystem
393    #[cfg(any(
394        target_os = "ios",
395        target_os = "macos",
396        target_os = "android",
397        target_os = "freebsd",
398        target_os = "openbsd",
399    ))]
400    #[cfg_attr(docsrs, doc(cfg(all())))]
401    pub fn blocks(&self) -> u64 {
402        self.0.f_blocks
403    }
404
405    /// Total data blocks in filesystem
406    #[cfg(target_os = "dragonfly")]
407    #[cfg_attr(docsrs, doc(cfg(all())))]
408    pub fn blocks(&self) -> libc::c_long {
409        self.0.f_blocks
410    }
411
412    /// Total data blocks in filesystem
413    #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))]
414    #[cfg_attr(docsrs, doc(cfg(all())))]
415    pub fn blocks(&self) -> u64 {
416        self.0.f_blocks
417    }
418
419    /// Total data blocks in filesystem
420    #[cfg(not(any(
421        target_os = "ios",
422        target_os = "macos",
423        target_os = "android",
424        target_os = "freebsd",
425        target_os = "openbsd",
426        target_os = "dragonfly",
427        all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32")))
428    )))]
429    #[cfg_attr(docsrs, doc(cfg(all())))]
430    pub fn blocks(&self) -> libc::c_ulong {
431        self.0.f_blocks
432    }
433
434    /// Free blocks in filesystem
435    #[cfg(any(
436        target_os = "ios",
437        target_os = "macos",
438        target_os = "android",
439        target_os = "freebsd",
440        target_os = "openbsd",
441    ))]
442    #[cfg_attr(docsrs, doc(cfg(all())))]
443    pub fn blocks_free(&self) -> u64 {
444        self.0.f_bfree
445    }
446
447    /// Free blocks in filesystem
448    #[cfg(target_os = "dragonfly")]
449    #[cfg_attr(docsrs, doc(cfg(all())))]
450    pub fn blocks_free(&self) -> libc::c_long {
451        self.0.f_bfree
452    }
453
454    /// Free blocks in filesystem
455    #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))]
456    #[cfg_attr(docsrs, doc(cfg(all())))]
457    pub fn blocks_free(&self) -> u64 {
458        self.0.f_bfree
459    }
460
461    /// Free blocks in filesystem
462    #[cfg(not(any(
463        target_os = "ios",
464        target_os = "macos",
465        target_os = "android",
466        target_os = "freebsd",
467        target_os = "openbsd",
468        target_os = "dragonfly",
469        all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32")))
470    )))]
471    #[cfg_attr(docsrs, doc(cfg(all())))]
472    pub fn blocks_free(&self) -> libc::c_ulong {
473        self.0.f_bfree
474    }
475
476    /// Free blocks available to unprivileged user
477    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
478    #[cfg_attr(docsrs, doc(cfg(all())))]
479    pub fn blocks_available(&self) -> u64 {
480        self.0.f_bavail
481    }
482
483    /// Free blocks available to unprivileged user
484    #[cfg(target_os = "dragonfly")]
485    #[cfg_attr(docsrs, doc(cfg(all())))]
486    pub fn blocks_available(&self) -> libc::c_long {
487        self.0.f_bavail
488    }
489
490    /// Free blocks available to unprivileged user
491    #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
492    #[cfg_attr(docsrs, doc(cfg(all())))]
493    pub fn blocks_available(&self) -> i64 {
494        self.0.f_bavail
495    }
496
497    /// Free blocks available to unprivileged user
498    #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))]
499    #[cfg_attr(docsrs, doc(cfg(all())))]
500    pub fn blocks_available(&self) -> u64 {
501        self.0.f_bavail
502    }
503
504    /// Free blocks available to unprivileged user
505    #[cfg(not(any(
506        target_os = "ios",
507        target_os = "macos",
508        target_os = "android",
509        target_os = "freebsd",
510        target_os = "openbsd",
511        target_os = "dragonfly",
512        all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32")))
513    )))]
514    #[cfg_attr(docsrs, doc(cfg(all())))]
515    pub fn blocks_available(&self) -> libc::c_ulong {
516        self.0.f_bavail
517    }
518
519    /// Total file nodes in filesystem
520    #[cfg(any(
521        target_os = "ios",
522        target_os = "macos",
523        target_os = "android",
524        target_os = "freebsd",
525        target_os = "openbsd",
526    ))]
527    #[cfg_attr(docsrs, doc(cfg(all())))]
528    pub fn files(&self) -> u64 {
529        self.0.f_files
530    }
531
532    /// Total file nodes in filesystem
533    #[cfg(target_os = "dragonfly")]
534    #[cfg_attr(docsrs, doc(cfg(all())))]
535    pub fn files(&self) -> libc::c_long {
536        self.0.f_files
537    }
538
539    /// Total file nodes in filesystem
540    #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))]
541    #[cfg_attr(docsrs, doc(cfg(all())))]
542    pub fn files(&self) -> libc::fsfilcnt_t {
543        self.0.f_files
544    }
545
546    /// Total file nodes in filesystem
547    #[cfg(not(any(
548        target_os = "ios",
549        target_os = "macos",
550        target_os = "android",
551        target_os = "freebsd",
552        target_os = "openbsd",
553        target_os = "dragonfly",
554        all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32")))
555    )))]
556    #[cfg_attr(docsrs, doc(cfg(all())))]
557    pub fn files(&self) -> libc::c_ulong {
558        self.0.f_files
559    }
560
561    /// Free file nodes in filesystem
562    #[cfg(any(
563            target_os = "android",
564            target_os = "ios",
565            target_os = "macos",
566            target_os = "openbsd"
567    ))]
568    #[cfg_attr(docsrs, doc(cfg(all())))]
569    pub fn files_free(&self) -> u64 {
570        self.0.f_ffree
571    }
572
573    /// Free file nodes in filesystem
574    #[cfg(target_os = "dragonfly")]
575    #[cfg_attr(docsrs, doc(cfg(all())))]
576    pub fn files_free(&self) -> libc::c_long {
577        self.0.f_ffree
578    }
579
580    /// Free file nodes in filesystem
581    #[cfg(target_os = "freebsd")]
582    #[cfg_attr(docsrs, doc(cfg(all())))]
583    pub fn files_free(&self) -> i64 {
584        self.0.f_ffree
585    }
586
587    /// Free file nodes in filesystem
588    #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))]
589    #[cfg_attr(docsrs, doc(cfg(all())))]
590    pub fn files_free(&self) -> libc::fsfilcnt_t {
591        self.0.f_ffree
592    }
593
594    /// Free file nodes in filesystem
595    #[cfg(not(any(
596        target_os = "ios",
597        target_os = "macos",
598        target_os = "android",
599        target_os = "freebsd",
600        target_os = "openbsd",
601        target_os = "dragonfly",
602        all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32")))
603    )))]
604    #[cfg_attr(docsrs, doc(cfg(all())))]
605    pub fn files_free(&self) -> libc::c_ulong {
606        self.0.f_ffree
607    }
608
609    /// Filesystem ID
610    pub fn filesystem_id(&self) -> fsid_t {
611        self.0.f_fsid
612    }
613}
614
615impl Debug for Statfs {
616    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
617        f.debug_struct("Statfs")
618            .field("optimal_transfer_size", &self.optimal_transfer_size())
619            .field("block_size", &self.block_size())
620            .field("blocks", &self.blocks())
621            .field("blocks_free", &self.blocks_free())
622            .field("blocks_available", &self.blocks_available())
623            .field("files", &self.files())
624            .field("files_free", &self.files_free())
625            .field("filesystem_id", &self.filesystem_id())
626            .finish()
627    }
628}
629
630/// Describes a mounted file system.
631///
632/// The result is OS-dependent.  For a portable alternative, see
633/// [`statvfs`](crate::sys::statvfs::statvfs).
634///
635/// # Arguments
636///
637/// `path` - Path to any file within the file system to describe
638pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
639    unsafe {
640        let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
641        let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?;
642        Errno::result(res).map(|_| Statfs(stat.assume_init()))
643    }
644}
645
646/// Describes a mounted file system.
647///
648/// The result is OS-dependent.  For a portable alternative, see
649/// [`fstatvfs`](crate::sys::statvfs::fstatvfs).
650///
651/// # Arguments
652///
653/// `fd` - File descriptor of any open file within the file system to describe
654pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
655    unsafe {
656        let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
657        Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr()))
658            .map(|_| Statfs(stat.assume_init()))
659    }
660}
661
662#[cfg(test)]
663mod test {
664    use std::fs::File;
665
666    use crate::sys::statfs::*;
667    use crate::sys::statvfs::*;
668    use std::path::Path;
669
670    #[test]
671    fn statfs_call() {
672        check_statfs("/tmp");
673        check_statfs("/dev");
674        check_statfs("/run");
675        check_statfs("/");
676    }
677
678    #[test]
679    fn fstatfs_call() {
680        check_fstatfs("/tmp");
681        check_fstatfs("/dev");
682        check_fstatfs("/run");
683        check_fstatfs("/");
684    }
685
686    fn check_fstatfs(path: &str) {
687        if !Path::new(path).exists() {
688            return;
689        }
690        let vfs = statvfs(path.as_bytes()).unwrap();
691        let file = File::open(path).unwrap();
692        let fs = fstatfs(&file).unwrap();
693        assert_fs_equals(fs, vfs);
694    }
695
696    fn check_statfs(path: &str) {
697        if !Path::new(path).exists() {
698            return;
699        }
700        let vfs = statvfs(path.as_bytes()).unwrap();
701        let fs = statfs(path.as_bytes()).unwrap();
702        assert_fs_equals(fs, vfs);
703    }
704
705    // The cast is not unnecessary on all platforms.
706    #[allow(clippy::unnecessary_cast)]
707    fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
708        assert_eq!(fs.files() as u64, vfs.files() as u64);
709        assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
710        assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
711    }
712
713    // This test is ignored because files_free/blocks_free can change after statvfs call and before
714    // statfs call.
715    #[test]
716    #[ignore]
717    fn statfs_call_strict() {
718        check_statfs_strict("/tmp");
719        check_statfs_strict("/dev");
720        check_statfs_strict("/run");
721        check_statfs_strict("/");
722    }
723
724    // This test is ignored because files_free/blocks_free can change after statvfs call and before
725    // fstatfs call.
726    #[test]
727    #[ignore]
728    fn fstatfs_call_strict() {
729        check_fstatfs_strict("/tmp");
730        check_fstatfs_strict("/dev");
731        check_fstatfs_strict("/run");
732        check_fstatfs_strict("/");
733    }
734
735    fn check_fstatfs_strict(path: &str) {
736        if !Path::new(path).exists() {
737            return;
738        }
739        let vfs = statvfs(path.as_bytes());
740        let file = File::open(path).unwrap();
741        let fs = fstatfs(&file);
742        assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
743    }
744
745    fn check_statfs_strict(path: &str) {
746        if !Path::new(path).exists() {
747            return;
748        }
749        let vfs = statvfs(path.as_bytes());
750        let fs = statfs(path.as_bytes());
751        assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
752    }
753
754    // The cast is not unnecessary on all platforms.
755    #[allow(clippy::unnecessary_cast)]
756    fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
757        assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
758        assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
759        assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
760        assert_eq!(fs.files() as u64, vfs.files() as u64);
761        assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
762        assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
763    }
764}