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