Skip to main content

which_fs/
lib.rs

1// SPDX-FileCopyrightText: 2026 Manuel Quarneti <mq1@ik.me>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4mod 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 = match data {
33        magic::FAT32 => FsKind::Fat32,
34        _ => FsKind::Unknown,
35    };
36
37    Ok(kind)
38}
39
40#[cfg(windows)]
41pub fn detect(path: &Path) -> windows::core::Result<FsKind> {
42    use std::os::windows::ffi::OsStrExt;
43    use windows::Win32::Foundation::MAX_PATH;
44    use windows::Win32::Storage::FileSystem::{GetVolumeInformationW, GetVolumePathNameW};
45    use windows::core::PCWSTR;
46
47    // Convert input path to null-terminated UTF-16 wide string
48    let path_wide: Vec<u16> = path
49        .as_os_str()
50        .encode_wide()
51        .chain(std::iter::once(0))
52        .collect();
53
54    // Get the Volume Path Name (Mount Point)
55    let mut volume_path = [0u16; MAX_PATH as usize];
56    unsafe {
57        GetVolumePathNameW(PCWSTR(path_wide.as_ptr()), &mut volume_path)?;
58    }
59
60    let mut fs_name_buffer = [0u16; 8];
61    unsafe {
62        GetVolumeInformationW(
63            PCWSTR(volume_path.as_ptr()),
64            None,
65            None,
66            None,
67            None,
68            Some(&mut fs_name_buffer),
69        )?;
70    }
71
72    let kind = match fs_name_buffer {
73        magic::FAT32 => FsKind::Fat32,
74        _ => FsKind::Unknown,
75    };
76
77    Ok(kind)
78}