eza/fs/mounts/
mod.rs

1// SPDX-FileCopyrightText: 2024 Christina Sørensen
2// SPDX-License-Identifier: EUPL-1.2
3//
4// SPDX-FileCopyrightText: 2023-2024 Christina Sørensen, eza contributors
5// SPDX-FileCopyrightText: 2014 Benjamin Sago
6// SPDX-License-Identifier: MIT
7use std::collections::HashMap;
8use std::path::PathBuf;
9use std::sync::OnceLock;
10
11#[cfg(target_os = "linux")]
12mod linux;
13#[cfg(target_os = "macos")]
14mod macos;
15
16#[cfg(target_os = "linux")]
17use linux::mounts;
18#[cfg(target_os = "macos")]
19use macos::mounts;
20
21/// Details of a mounted filesystem.
22#[derive(Clone)]
23pub struct MountedFs {
24    pub dest: PathBuf,
25    pub fstype: String,
26    pub source: String,
27}
28
29#[derive(Debug)]
30#[non_exhaustive]
31pub enum Error {
32    #[cfg(target_os = "macos")]
33    GetFSStatError(i32),
34    #[cfg(target_os = "linux")]
35    IOError(std::io::Error),
36}
37
38impl std::error::Error for Error {}
39
40impl std::fmt::Display for Error {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        // Allow unreachable_patterns for windows build
43        #[allow(unreachable_patterns)]
44        match self {
45            #[cfg(target_os = "macos")]
46            Error::GetFSStatError(err) => write!(f, "getfsstat failed: {err}"),
47            #[cfg(target_os = "linux")]
48            Error::IOError(err) => write!(f, "failed to read /proc/mounts: {err}"),
49            _ => write!(f, "Unknown error"),
50        }
51    }
52}
53
54// A lazily initialised static map of all mounted file systems.
55//
56// The map contains a mapping from the mounted directory path to the
57// corresponding mount information. If there's an error retrieving the mount
58// list or if we're not running on Linux or Mac, the map will be empty.
59//
60// Initialise this at application start so we don't have to look the details
61// up for every directory. Ideally this would only be done if the --mounts
62// option is specified which will be significantly easier once the move
63// to `clap` is complete.
64pub(super) fn all_mounts() -> &'static HashMap<PathBuf, MountedFs> {
65    static ALL_MOUNTS: OnceLock<HashMap<PathBuf, MountedFs>> = OnceLock::new();
66
67    ALL_MOUNTS.get_or_init(|| {
68        // Allow unused_mut for windows build
69        #[allow(unused_mut)]
70        let mut mount_map: HashMap<PathBuf, MountedFs> = HashMap::new();
71
72        #[cfg(any(target_os = "linux", target_os = "macos"))]
73        if let Ok(mounts) = mounts() {
74            for mount in mounts {
75                mount_map.insert(mount.dest.clone(), mount);
76            }
77        }
78
79        mount_map
80    })
81}