nix/sys/
statfs.rs

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