1 use std::fmt::{self, Debug};
2 use std::mem;
3 use std::os::unix::io::AsRawFd;
4 #[cfg(not(any(target_os = "linux", target_os = "android")))]
5 use std::ffi::CStr;
6 
7 use crate::{NixPath, Result, errno::Errno};
8 
9 #[cfg(target_os = "android")]
10 pub type fsid_t = libc::__fsid_t;
11 #[cfg(not(target_os = "android"))]
12 pub type fsid_t = libc::fsid_t;
13 
14 #[derive(Clone, Copy)]
15 #[repr(transparent)]
16 pub struct Statfs(libc::statfs);
17 
18 #[cfg(target_os = "freebsd")]
19 type fs_type_t = u32;
20 #[cfg(target_os = "android")]
21 type fs_type_t = libc::c_ulong;
22 #[cfg(all(target_os = "linux", target_arch = "s390x"))]
23 type fs_type_t = libc::c_uint;
24 #[cfg(all(target_os = "linux", target_env = "musl"))]
25 type fs_type_t = libc::c_ulong;
26 #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
27 type fs_type_t = libc::__fsword_t;
28 
29 #[cfg(any(
30     target_os = "freebsd",
31     target_os = "android",
32     all(target_os = "linux", target_arch = "s390x"),
33     all(target_os = "linux", target_env = "musl"),
34     all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))),
35 ))]
36 #[derive(Eq, Copy, Clone, PartialEq, Debug)]
37 pub struct FsType(pub fs_type_t);
38 
39 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
40 pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
41 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
42 pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
43 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
44 pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
45 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
46 pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
47 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
48 pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t);
49 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
50 pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
51 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
52 pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
53 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
54 pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
55 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
56 pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
57 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
58 pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t);
59 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
60 pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
61 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
62 pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
63 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
64 pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
65 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
66 pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
67 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
68 pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
69 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
70 pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
71 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
72 pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
73 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
74 pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
75 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
76 pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
77 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
78 pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
79 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
80 pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
81 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
82 pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
83 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
84 pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
85 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
86 pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
87 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
88 pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
89 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
90 pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
91 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
92 pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
93 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
94 pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
95 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
96 pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
97 
98 
99 impl Statfs {
100     /// Magic code defining system type
101     #[cfg(not(any(
102         target_os = "openbsd",
103         target_os = "dragonfly",
104         target_os = "ios",
105         target_os = "macos"
106     )))]
filesystem_type(&self) -> FsType107     pub fn filesystem_type(&self) -> FsType {
108         FsType(self.0.f_type)
109     }
110 
111     /// Magic code defining system type
112     #[cfg(not(any(target_os = "linux", target_os = "android")))]
filesystem_type_name(&self) -> &str113     pub fn filesystem_type_name(&self) -> &str {
114         let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
115         c_str.to_str().unwrap()
116     }
117 
118     /// Optimal transfer block size
119     #[cfg(any(target_os = "ios", target_os = "macos"))]
optimal_transfer_size(&self) -> i32120     pub fn optimal_transfer_size(&self) -> i32 {
121         self.0.f_iosize
122     }
123 
124     /// Optimal transfer block size
125     #[cfg(target_os = "openbsd")]
optimal_transfer_size(&self) -> u32126     pub fn optimal_transfer_size(&self) -> u32 {
127         self.0.f_iosize
128     }
129 
130     /// Optimal transfer block size
131     #[cfg(all(target_os = "linux", target_arch = "s390x"))]
optimal_transfer_size(&self) -> u32132     pub fn optimal_transfer_size(&self) -> u32 {
133         self.0.f_bsize
134     }
135 
136     /// Optimal transfer block size
137     #[cfg(any(
138         target_os = "android",
139         all(target_os = "linux", target_env = "musl")
140     ))]
optimal_transfer_size(&self) -> libc::c_ulong141     pub fn optimal_transfer_size(&self) -> libc::c_ulong {
142         self.0.f_bsize
143     }
144 
145     /// Optimal transfer block size
146     #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
optimal_transfer_size(&self) -> libc::__fsword_t147     pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
148         self.0.f_bsize
149     }
150 
151     /// Optimal transfer block size
152     #[cfg(target_os = "dragonfly")]
optimal_transfer_size(&self) -> libc::c_long153     pub fn optimal_transfer_size(&self) -> libc::c_long {
154         self.0.f_iosize
155     }
156 
157     /// Optimal transfer block size
158     #[cfg(target_os = "freebsd")]
optimal_transfer_size(&self) -> u64159     pub fn optimal_transfer_size(&self) -> u64 {
160         self.0.f_iosize
161     }
162 
163     /// Size of a block
164     #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
block_size(&self) -> u32165     pub fn block_size(&self) -> u32 {
166         self.0.f_bsize
167     }
168 
169     /// Size of a block
170     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
171     #[cfg(all(target_os = "linux", target_arch = "s390x"))]
block_size(&self) -> u32172     pub fn block_size(&self) -> u32 {
173         self.0.f_bsize
174     }
175 
176     /// Size of a block
177     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
178     #[cfg(all(target_os = "linux", target_env = "musl"))]
block_size(&self) -> libc::c_ulong179     pub fn block_size(&self) -> libc::c_ulong {
180         self.0.f_bsize
181     }
182 
183     /// Size of a block
184     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
185     #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
block_size(&self) -> libc::__fsword_t186     pub fn block_size(&self) -> libc::__fsword_t {
187         self.0.f_bsize
188     }
189 
190     /// Size of a block
191     #[cfg(target_os = "freebsd")]
block_size(&self) -> u64192     pub fn block_size(&self) -> u64 {
193         self.0.f_bsize
194     }
195 
196     /// Size of a block
197     #[cfg(target_os = "android")]
block_size(&self) -> libc::c_ulong198     pub fn block_size(&self) -> libc::c_ulong {
199         self.0.f_bsize
200     }
201 
202     /// Size of a block
203     #[cfg(target_os = "dragonfly")]
block_size(&self) -> libc::c_long204     pub fn block_size(&self) -> libc::c_long {
205         self.0.f_bsize
206     }
207 
208     /// Maximum length of filenames
209     #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
maximum_name_length(&self) -> u32210     pub fn maximum_name_length(&self) -> u32 {
211         self.0.f_namemax
212     }
213 
214     /// Maximum length of filenames
215     #[cfg(all(target_os = "linux", target_arch = "s390x"))]
maximum_name_length(&self) -> u32216     pub fn maximum_name_length(&self) -> u32 {
217         self.0.f_namelen
218     }
219 
220     /// Maximum length of filenames
221     #[cfg(all(target_os = "linux", target_env = "musl"))]
maximum_name_length(&self) -> libc::c_ulong222     pub fn maximum_name_length(&self) -> libc::c_ulong {
223         self.0.f_namelen
224     }
225 
226     /// Maximum length of filenames
227     #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
maximum_name_length(&self) -> libc::__fsword_t228     pub fn maximum_name_length(&self) -> libc::__fsword_t {
229         self.0.f_namelen
230     }
231 
232     /// Maximum length of filenames
233     #[cfg(target_os = "android")]
maximum_name_length(&self) -> libc::c_ulong234     pub fn maximum_name_length(&self) -> libc::c_ulong {
235         self.0.f_namelen
236     }
237 
238     /// Total data blocks in filesystem
239     #[cfg(any(
240         target_os = "ios",
241         target_os = "macos",
242         target_os = "android",
243         target_os = "freebsd",
244         target_os = "openbsd",
245     ))]
blocks(&self) -> u64246     pub fn blocks(&self) -> u64 {
247         self.0.f_blocks
248     }
249 
250     /// Total data blocks in filesystem
251     #[cfg(target_os = "dragonfly")]
blocks(&self) -> libc::c_long252     pub fn blocks(&self) -> libc::c_long {
253         self.0.f_blocks
254     }
255 
256     /// Total data blocks in filesystem
257     #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
blocks(&self) -> u64258     pub fn blocks(&self) -> u64 {
259         self.0.f_blocks
260     }
261 
262     /// Total data blocks in filesystem
263     #[cfg(not(any(
264         target_os = "ios",
265         target_os = "macos",
266         target_os = "android",
267         target_os = "freebsd",
268         target_os = "openbsd",
269         target_os = "dragonfly",
270         all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
271     )))]
blocks(&self) -> libc::c_ulong272     pub fn blocks(&self) -> libc::c_ulong {
273         self.0.f_blocks
274     }
275 
276     /// Free 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_free(&self) -> u64284     pub fn blocks_free(&self) -> u64 {
285         self.0.f_bfree
286     }
287 
288     /// Free blocks in filesystem
289     #[cfg(target_os = "dragonfly")]
blocks_free(&self) -> libc::c_long290     pub fn blocks_free(&self) -> libc::c_long {
291         self.0.f_bfree
292     }
293 
294     /// Free blocks in filesystem
295     #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
blocks_free(&self) -> u64296     pub fn blocks_free(&self) -> u64 {
297         self.0.f_bfree
298     }
299 
300     /// Free 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_free(&self) -> libc::c_ulong310     pub fn blocks_free(&self) -> libc::c_ulong {
311         self.0.f_bfree
312     }
313 
314     /// Free blocks available to unprivileged user
315     #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
blocks_available(&self) -> u64316     pub fn blocks_available(&self) -> u64 {
317         self.0.f_bavail
318     }
319 
320     /// Free blocks available to unprivileged user
321     #[cfg(target_os = "dragonfly")]
blocks_available(&self) -> libc::c_long322     pub fn blocks_available(&self) -> libc::c_long {
323         self.0.f_bavail
324     }
325 
326     /// Free blocks available to unprivileged user
327     #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
blocks_available(&self) -> i64328     pub fn blocks_available(&self) -> i64 {
329         self.0.f_bavail
330     }
331 
332     /// Free blocks available to unprivileged user
333     #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
blocks_available(&self) -> u64334     pub fn blocks_available(&self) -> u64 {
335         self.0.f_bavail
336     }
337 
338     /// Free blocks available to unprivileged user
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_available(&self) -> libc::c_ulong348     pub fn blocks_available(&self) -> libc::c_ulong {
349         self.0.f_bavail
350     }
351 
352     /// Total file nodes in filesystem
353     #[cfg(any(
354         target_os = "ios",
355         target_os = "macos",
356         target_os = "android",
357         target_os = "freebsd",
358         target_os = "openbsd",
359     ))]
files(&self) -> u64360     pub fn files(&self) -> u64 {
361         self.0.f_files
362     }
363 
364     /// Total file nodes in filesystem
365     #[cfg(target_os = "dragonfly")]
files(&self) -> libc::c_long366     pub fn files(&self) -> libc::c_long {
367         self.0.f_files
368     }
369 
370     /// Total file nodes in filesystem
371     #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
files(&self) -> libc::fsfilcnt_t372     pub fn files(&self) -> libc::fsfilcnt_t {
373         self.0.f_files
374     }
375 
376     /// Total file nodes in filesystem
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     )))]
files(&self) -> libc::c_ulong386     pub fn files(&self) -> libc::c_ulong {
387         self.0.f_files
388     }
389 
390     /// Free file nodes in filesystem
391     #[cfg(any(
392             target_os = "android",
393             target_os = "ios",
394             target_os = "macos",
395             target_os = "openbsd"
396     ))]
files_free(&self) -> u64397     pub fn files_free(&self) -> u64 {
398         self.0.f_ffree
399     }
400 
401     /// Free file nodes in filesystem
402     #[cfg(target_os = "dragonfly")]
files_free(&self) -> libc::c_long403     pub fn files_free(&self) -> libc::c_long {
404         self.0.f_ffree
405     }
406 
407     /// Free file nodes in filesystem
408     #[cfg(target_os = "freebsd")]
files_free(&self) -> i64409     pub fn files_free(&self) -> i64 {
410         self.0.f_ffree
411     }
412 
413     /// Free file nodes in filesystem
414     #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
files_free(&self) -> libc::fsfilcnt_t415     pub fn files_free(&self) -> libc::fsfilcnt_t {
416         self.0.f_ffree
417     }
418 
419     /// Free file nodes in filesystem
420     #[cfg(not(any(
421         target_os = "ios",
422         target_os = "macos",
423         target_os = "android",
424         target_os = "freebsd",
425         target_os = "openbsd",
426         target_os = "dragonfly",
427         all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
428     )))]
files_free(&self) -> libc::c_ulong429     pub fn files_free(&self) -> libc::c_ulong {
430         self.0.f_ffree
431     }
432 
433     /// Filesystem ID
filesystem_id(&self) -> fsid_t434     pub fn filesystem_id(&self) -> fsid_t {
435         self.0.f_fsid
436     }
437 }
438 
439 impl Debug for Statfs {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result440     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
441         f.debug_struct("Statfs")
442             .field("optimal_transfer_size", &self.optimal_transfer_size())
443             .field("block_size", &self.block_size())
444             .field("blocks", &self.blocks())
445             .field("blocks_free", &self.blocks_free())
446             .field("blocks_available", &self.blocks_available())
447             .field("files", &self.files())
448             .field("files_free", &self.files_free())
449             .field("filesystem_id", &self.filesystem_id())
450             .finish()
451     }
452 }
453 
statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs>454 pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
455     unsafe {
456         let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
457         let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?;
458         Errno::result(res).map(|_| Statfs(stat.assume_init()))
459     }
460 }
461 
fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs>462 pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
463     unsafe {
464         let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
465         Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr()))
466             .map(|_| Statfs(stat.assume_init()))
467     }
468 }
469 
470 #[cfg(test)]
471 mod test {
472     use std::fs::File;
473 
474     use crate::sys::statfs::*;
475     use crate::sys::statvfs::*;
476     use std::path::Path;
477 
478     #[test]
statfs_call()479     fn statfs_call() {
480         check_statfs("/tmp");
481         check_statfs("/dev");
482         check_statfs("/run");
483         check_statfs("/");
484     }
485 
486     #[test]
fstatfs_call()487     fn fstatfs_call() {
488         check_fstatfs("/tmp");
489         check_fstatfs("/dev");
490         check_fstatfs("/run");
491         check_fstatfs("/");
492     }
493 
check_fstatfs(path: &str)494     fn check_fstatfs(path: &str) {
495         if !Path::new(path).exists() {
496             return;
497         }
498         let vfs = statvfs(path.as_bytes()).unwrap();
499         let file = File::open(path).unwrap();
500         let fs = fstatfs(&file).unwrap();
501         assert_fs_equals(fs, vfs);
502     }
503 
check_statfs(path: &str)504     fn check_statfs(path: &str) {
505         if !Path::new(path).exists() {
506             return;
507         }
508         let vfs = statvfs(path.as_bytes()).unwrap();
509         let fs = statfs(path.as_bytes()).unwrap();
510         assert_fs_equals(fs, vfs);
511     }
512 
assert_fs_equals(fs: Statfs, vfs: Statvfs)513     fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
514         assert_eq!(fs.files() as u64, vfs.files() as u64);
515         assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
516         assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
517     }
518 
519     // This test is ignored because files_free/blocks_free can change after statvfs call and before
520     // statfs call.
521     #[test]
522     #[ignore]
statfs_call_strict()523     fn statfs_call_strict() {
524         check_statfs_strict("/tmp");
525         check_statfs_strict("/dev");
526         check_statfs_strict("/run");
527         check_statfs_strict("/");
528     }
529 
530     // This test is ignored because files_free/blocks_free can change after statvfs call and before
531     // fstatfs call.
532     #[test]
533     #[ignore]
fstatfs_call_strict()534     fn fstatfs_call_strict() {
535         check_fstatfs_strict("/tmp");
536         check_fstatfs_strict("/dev");
537         check_fstatfs_strict("/run");
538         check_fstatfs_strict("/");
539     }
540 
check_fstatfs_strict(path: &str)541     fn check_fstatfs_strict(path: &str) {
542         if !Path::new(path).exists() {
543             return;
544         }
545         let vfs = statvfs(path.as_bytes());
546         let file = File::open(path).unwrap();
547         let fs = fstatfs(&file);
548         assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
549     }
550 
check_statfs_strict(path: &str)551     fn check_statfs_strict(path: &str) {
552         if !Path::new(path).exists() {
553             return;
554         }
555         let vfs = statvfs(path.as_bytes());
556         let fs = statfs(path.as_bytes());
557         assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
558     }
559 
assert_fs_equals_strict(fs: Statfs, vfs: Statvfs)560     fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
561         assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
562         assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
563         assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
564         assert_eq!(fs.files() as u64, vfs.files() as u64);
565         assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
566         assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
567     }
568 }
569