filesystem_kind/lib.rs
1#![warn(clippy::pedantic)]
2#![warn(clippy::nursery)]
3use std::fs::File;
4
5/// The kind of filesystem that a file resides on.
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum FileSystemKind {
8 /// A recognized filesystem.
9 Recognized(FileSystemName),
10 /// An unrecognized filesystem.
11 Unrecognized(Box<String>),
12 // todo: is there a better way to keep this pointer-sized? `Box<str>` is 2 pointer sizes :(
13 // todo: should this be `Option<Box<_>>`?
14 // todo: what order should enum variants be in?
15 // todo: add `Unsupported` variant for OS's where
16 // this information can't be easily queried?
17}
18
19/// An enum representing all recognized filesystem names.
20#[non_exhaustive]
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22#[repr(u16)]
23// todo: come up with naming conventions,
24// i.e. should they all end in "fs"?
25// Or should we stick to the common renderings of each fs?
26pub enum FileSystemName {
27 Autofs,
28 Btrfs,
29 Cdfs,
30 Devfs,
31 Ext2,
32 Ext3,
33 Ext4,
34 Fat,
35 Fat32,
36 Fatx,
37 Fdescfs,
38 Fusefs,
39 Linprocfs, // todo: should this just be procfs?
40 Linsysfs, // todo: should this just be sysfs?
41 Mqueuefs,
42 Nfs,
43 Ntfs,
44 Nullfs,
45 Procfs,
46 Tmpfs,
47 Ufs,
48 Zfs,
49}
50
51/// An extension trait for `File` that allows querying the kind of filesystem it resides on.
52// todo: is there a possible error condition that isn't covered by `std::io::Error`?
53pub trait FileExt {
54 /// Query the filesystem that this file resides on.
55 ///
56 /// # Errors
57 ///
58 /// Note that a variant of `std::io::Error` may be returned,
59 /// which can indicate a number of error conditions
60 /// such as corrupted data, insufficient permissions, etc.
61 fn filesystem(&self) -> Result<FileSystemKind, std::io::Error>;
62}
63
64cfg_if::cfg_if! {
65 if #[cfg(target_os = "freebsd")] {
66 mod freebsd;
67 use freebsd::filesystem;
68 } else if #[cfg(target_os = "windows")] {
69 mod windows;
70 use windows::filesystem;
71 } else if #[cfg(target_os = "macos")] {
72 mod macos;
73 use macos::filesystem;
74 } else if #[cfg(target_os = "linux")] {
75 mod linux;
76 use linux::filesystem;
77 } else {
78 // todo: ios, android, and other bsd's
79 // todo: unix-y/posix-y fallback?
80 }
81}
82
83impl FileExt for File {
84 fn filesystem(&self) -> Result<FileSystemKind, std::io::Error> {
85 filesystem(self)
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn look_for_unrecognized_filesystems() {
95 use std::collections::HashSet;
96 use walkdir::WalkDir;
97
98 let mut set = HashSet::new();
99
100 for entry in WalkDir::new("/").into_iter().filter_map(Result::ok) {
101 if let Ok(file) = File::open(entry.path()) {
102 if let Ok(FileSystemKind::Unrecognized(s)) = file.filesystem() {
103 // panic!("unknown filesystem: {:?}", s);
104 set.insert(s);
105 }
106 }
107 }
108
109 if !set.is_empty() {
110 panic!("{:?}", set);
111 }
112 }
113}