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