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