1mod magic;
5
6use std::{fmt, path::Path};
7
8pub enum FsKind {
9 Fat32,
10 Unknown,
11}
12
13impl fmt::Display for FsKind {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 FsKind::Fat32 => write!(f, "FAT32"),
17 FsKind::Unknown => write!(f, "Unknown"),
18 }
19 }
20}
21
22#[cfg(unix)]
23pub fn detect(path: &Path) -> rustix::io::Result<FsKind> {
24 let stat = rustix::fs::statfs(path)?;
25
26 #[cfg(target_os = "linux")]
27 let data = stat.f_type;
28
29 #[cfg(target_os = "macos")]
30 let data = stat.f_fstypename;
31
32 let kind = which_kind(data);
33
34 Ok(kind)
35}
36
37#[cfg(windows)]
38pub fn detect(path: &Path) -> windows::core::Result<FsKind> {
39 use std::os::windows::ffi::OsStrExt;
40 use windows::Win32::Foundation::MAX_PATH;
41 use windows::Win32::Storage::FileSystem::{GetVolumeInformationW, GetVolumePathNameW};
42 use windows::core::PCWSTR;
43
44 let path_wide: Vec<u16> = path
46 .as_os_str()
47 .encode_wide()
48 .chain(std::iter::once(0))
49 .collect();
50
51 let mut volume_path = [0u16; MAX_PATH as usize];
53 unsafe {
54 GetVolumePathNameW(PCWSTR(path_wide.as_ptr()), &mut volume_path)?;
55 }
56
57 let mut fs_name_buffer = [0u16; 8];
58 unsafe {
59 GetVolumeInformationW(
60 PCWSTR(volume_path.as_ptr()),
61 None,
62 None,
63 None,
64 None,
65 Some(&mut fs_name_buffer),
66 )?;
67 }
68
69 let kind = which_kind(fs_name_buffer);
70
71 Ok(kind)
72}
73
74#[cfg(target_os = "macos")]
75type RawKind = [i8; 16];
76
77#[cfg(target_os = "linux")]
78type RawKind = rustix::fs::FsWord;
79
80#[cfg(windows)]
81type RawKind = [u16; 8];
82
83fn which_kind(raw: RawKind) -> FsKind {
84 match raw {
85 magic::FAT32 => FsKind::Fat32,
86 _ => FsKind::Unknown,
87 }
88}