1 //! Get filesystem statistics, non-portably
2 //!
3 //! See [`statvfs`](crate::sys::statvfs) for a portable alternative.
4 use std::fmt::{self, Debug};
5 use std::mem;
6 use std::os::unix::io::AsRawFd;
7 #[cfg(not(any(target_os = "linux", target_os = "android")))]
8 use std::ffi::CStr;
9 
10 use crate::{NixPath, Result, errno::Errno};
11 
12 /// Identifies a mounted file system
13 #[cfg(target_os = "android")]
14 pub type fsid_t = libc::__fsid_t;
15 /// Identifies a mounted file system
16 #[cfg(not(target_os = "android"))]
17 pub type fsid_t = libc::fsid_t;
18 
19 /// Describes a mounted file system
20 #[derive(Clone, Copy)]
21 #[repr(transparent)]
22 pub struct Statfs(libc::statfs);
23 
24 #[cfg(target_os = "freebsd")]
25 type fs_type_t = u32;
26 #[cfg(target_os = "android")]
27 type fs_type_t = libc::c_ulong;
28 #[cfg(all(target_os = "linux", target_arch = "s390x"))]
29 type fs_type_t = libc::c_uint;
30 #[cfg(all(target_os = "linux", target_env = "musl"))]
31 type fs_type_t = libc::c_ulong;
32 #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
33 type 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)]
44 pub 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)]
50 pub 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)]
53 pub 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)]
56 pub 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)]
59 pub 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)]
62 pub 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)]
65 pub 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)]
68 pub 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)]
71 pub 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)]
74 pub 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)]
77 pub 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)]
80 pub 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)]
83 pub 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)]
86 pub 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)]
89 pub 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)]
92 pub 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)]
95 pub 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)]
98 pub 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)]
101 pub 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)]
104 pub 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)]
107 pub 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)]
110 pub 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)]
113 pub 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)]
116 pub 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)]
119 pub 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)]
122 pub 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)]
125 pub 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)]
128 pub 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)]
131 pub 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)]
134 pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
135 
136 
137 impl 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     )))]
filesystem_type(&self) -> FsType145     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")))]
filesystem_type_name(&self) -> &str151     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"))]
optimal_transfer_size(&self) -> i32158     pub fn optimal_transfer_size(&self) -> i32 {
159         self.0.f_iosize
160     }
161 
162     /// Optimal transfer block size
163     #[cfg(target_os = "openbsd")]
optimal_transfer_size(&self) -> u32164     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"))]
optimal_transfer_size(&self) -> u32170     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     ))]
optimal_transfer_size(&self) -> libc::c_ulong179     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"))))]
optimal_transfer_size(&self) -> libc::__fsword_t185     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")]
optimal_transfer_size(&self) -> libc::c_long191     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")]
optimal_transfer_size(&self) -> u64197     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"))]
block_size(&self) -> u32203     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"))]
block_size(&self) -> u32210     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"))]
block_size(&self) -> libc::c_ulong217     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"))))]
block_size(&self) -> libc::__fsword_t224     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")]
block_size(&self) -> u64230     pub fn block_size(&self) -> u64 {
231         self.0.f_bsize
232     }
233 
234     /// Size of a block
235     #[cfg(target_os = "android")]
block_size(&self) -> libc::c_ulong236     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")]
block_size(&self) -> libc::c_long242     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"))]
maximum_name_length(&self) -> u32248     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"))]
maximum_name_length(&self) -> u32254     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"))]
maximum_name_length(&self) -> libc::c_ulong260     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"))))]
maximum_name_length(&self) -> libc::__fsword_t266     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")]
maximum_name_length(&self) -> libc::c_ulong272     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     ))]
blocks(&self) -> u64284     pub fn blocks(&self) -> u64 {
285         self.0.f_blocks
286     }
287 
288     /// Total data blocks in filesystem
289     #[cfg(target_os = "dragonfly")]
blocks(&self) -> libc::c_long290     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"))))]
blocks(&self) -> u64296     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     )))]
blocks(&self) -> libc::c_ulong310     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     ))]
blocks_free(&self) -> u64322     pub fn blocks_free(&self) -> u64 {
323         self.0.f_bfree
324     }
325 
326     /// Free blocks in filesystem
327     #[cfg(target_os = "dragonfly")]
blocks_free(&self) -> libc::c_long328     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"))))]
blocks_free(&self) -> u64334     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     )))]
blocks_free(&self) -> libc::c_ulong348     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"))]
blocks_available(&self) -> u64354     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")]
blocks_available(&self) -> libc::c_long360     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"))]
blocks_available(&self) -> i64366     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"))))]
blocks_available(&self) -> u64372     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     )))]
blocks_available(&self) -> libc::c_ulong386     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     ))]
files(&self) -> u64398     pub fn files(&self) -> u64 {
399         self.0.f_files
400     }
401 
402     /// Total file nodes in filesystem
403     #[cfg(target_os = "dragonfly")]
files(&self) -> libc::c_long404     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"))))]
files(&self) -> libc::fsfilcnt_t410     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     )))]
files(&self) -> libc::c_ulong424     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     ))]
files_free(&self) -> u64435     pub fn files_free(&self) -> u64 {
436         self.0.f_ffree
437     }
438 
439     /// Free file nodes in filesystem
440     #[cfg(target_os = "dragonfly")]
files_free(&self) -> libc::c_long441     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")]
files_free(&self) -> i64447     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"))))]
files_free(&self) -> libc::fsfilcnt_t453     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     )))]
files_free(&self) -> libc::c_ulong467     pub fn files_free(&self) -> libc::c_ulong {
468         self.0.f_ffree
469     }
470 
471     /// Filesystem ID
filesystem_id(&self) -> fsid_t472     pub fn filesystem_id(&self) -> fsid_t {
473         self.0.f_fsid
474     }
475 }
476 
477 impl Debug for Statfs {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result478     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
statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs>500 pub 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
fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs>516 pub 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)]
525 mod 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]
statfs_call()533     fn statfs_call() {
534         check_statfs("/tmp");
535         check_statfs("/dev");
536         check_statfs("/run");
537         check_statfs("/");
538     }
539 
540     #[test]
fstatfs_call()541     fn fstatfs_call() {
542         check_fstatfs("/tmp");
543         check_fstatfs("/dev");
544         check_fstatfs("/run");
545         check_fstatfs("/");
546     }
547 
check_fstatfs(path: &str)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 
check_statfs(path: &str)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 
assert_fs_equals(fs: Statfs, vfs: Statvfs)567     fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
568         assert_eq!(fs.files() as u64, vfs.files() as u64);
569         assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
570         assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
571     }
572 
573     // This test is ignored because files_free/blocks_free can change after statvfs call and before
574     // statfs call.
575     #[test]
576     #[ignore]
statfs_call_strict()577     fn statfs_call_strict() {
578         check_statfs_strict("/tmp");
579         check_statfs_strict("/dev");
580         check_statfs_strict("/run");
581         check_statfs_strict("/");
582     }
583 
584     // This test is ignored because files_free/blocks_free can change after statvfs call and before
585     // fstatfs call.
586     #[test]
587     #[ignore]
fstatfs_call_strict()588     fn fstatfs_call_strict() {
589         check_fstatfs_strict("/tmp");
590         check_fstatfs_strict("/dev");
591         check_fstatfs_strict("/run");
592         check_fstatfs_strict("/");
593     }
594 
check_fstatfs_strict(path: &str)595     fn check_fstatfs_strict(path: &str) {
596         if !Path::new(path).exists() {
597             return;
598         }
599         let vfs = statvfs(path.as_bytes());
600         let file = File::open(path).unwrap();
601         let fs = fstatfs(&file);
602         assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
603     }
604 
check_statfs_strict(path: &str)605     fn check_statfs_strict(path: &str) {
606         if !Path::new(path).exists() {
607             return;
608         }
609         let vfs = statvfs(path.as_bytes());
610         let fs = statfs(path.as_bytes());
611         assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
612     }
613 
assert_fs_equals_strict(fs: Statfs, vfs: Statvfs)614     fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
615         assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
616         assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
617         assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
618         assert_eq!(fs.files() as u64, vfs.files() as u64);
619         assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
620         assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
621     }
622 }
623