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