1use color_eyre::eyre::eyre;
10use color_eyre::eyre::ContextCompat;
11use color_eyre::Result;
12use faccess::{AccessMode, PathExt};
13
14use std::env;
15
16use std::path::Path;
17use std::path::PathBuf;
18use std::process::Command;
19use sysinfo::Disks;
20
21pub fn get_default_mount_point() -> Result<(String, PathBuf)> {
24 let disks = Disks::new_with_refreshed_list();
26
27 let exe_path = env::current_exe()?;
29
30 for disk in disks.list() {
32 if exe_path.starts_with(disk.mount_point()) {
33 return Ok((
34 disk.name().to_string_lossy().into(),
35 disk.mount_point().to_path_buf(),
36 ));
37 }
38 }
39 Err(eyre!("Cannot find the default mount point"))
40}
41
42fn has_read_write_access(path: PathBuf) -> bool {
44 let check_access = |mode, access_type| match path.access(mode) {
45 Ok(_) => {
46 debug!("{} access granted for {:?}", access_type, path);
47 true
48 }
49 Err(_) => {
50 debug!("{} access denied for {:?}", access_type, path);
51 false
52 }
53 };
54
55 let read = check_access(AccessMode::READ, "Read");
56 let write = check_access(AccessMode::WRITE, "Write");
57
58 read && write
59}
60
61pub fn get_list_of_available_drives_and_available_space(
66) -> Result<Vec<(String, PathBuf, u64, bool)>> {
67 let disks = Disks::new_with_refreshed_list();
68 let mut drives: Vec<(String, PathBuf, u64, bool)> = Vec::new();
69
70 let default_mountpoint = match get_default_mount_point() {
71 Ok((_name, mountpoint)) => mountpoint,
72 Err(_) => PathBuf::new(),
73 };
74
75 for disk in disks.list() {
76 let disk_info = (
77 disk.name()
78 .to_string_lossy()
79 .into_owned()
80 .trim()
81 .to_string(),
82 disk.mount_point().to_path_buf(),
83 disk.available_space(),
84 has_read_write_access(disk.mount_point().to_path_buf())
85 || default_mountpoint == disk.mount_point().to_path_buf(),
86 );
87
88 if !drives
91 .iter()
92 .any(|drive| drive.0 == disk_info.0 && drive.2 == disk_info.2)
93 {
94 debug!("[ADD] Disk added: {:?}", disk_info);
95 drives.push(disk_info);
96 } else {
97 debug!("[SKIP] Disk {:?} already added before.", disk_info);
98 }
99 }
100
101 debug!("Drives detected: {:?}", drives);
102 Ok(drives)
103}
104
105pub fn open_folder(path: &str) -> std::io::Result<()> {
107 if Path::new(path).exists() {
108 #[cfg(target_os = "macos")]
109 Command::new("open").arg(path).spawn()?.wait()?;
110 #[cfg(target_os = "windows")]
111 Command::new("explorer").arg(path).spawn()?.wait()?;
112 #[cfg(target_os = "linux")]
113 Command::new("xdg-open").arg(path).spawn()?.wait()?;
114 } else {
115 error!("Path does not exist: {}", path);
116 }
117 Ok(())
118}
119
120#[cfg(unix)]
121pub fn get_primary_mount_point() -> PathBuf {
122 PathBuf::from("/")
123}
124#[cfg(windows)]
125pub fn get_primary_mount_point() -> PathBuf {
126 PathBuf::from("C:\\")
127}
128
129pub fn get_primary_mount_point_name() -> Result<String> {
131 let primary_mount_point = get_primary_mount_point();
132 let available_drives = get_list_of_available_drives_and_available_space()?;
133
134 available_drives
135 .iter()
136 .find(|(_, mount_point, _, _)| mount_point == &primary_mount_point)
137 .map(|(name, _, _, _)| name.clone())
138 .ok_or_else(|| eyre!("Unable to find the name of the primary mount point"))
139}
140
141pub fn get_available_space_b(storage_mountpoint: &PathBuf) -> Result<usize> {
143 let disks = Disks::new_with_refreshed_list();
144 if tracing::level_enabled!(tracing::Level::DEBUG) {
145 for disk in disks.list() {
146 let res = disk.mount_point() == storage_mountpoint;
147 debug!(
148 "Disk: {disk:?} is equal to '{:?}': {res:?}",
149 storage_mountpoint,
150 );
151 }
152 }
153
154 let available_space_b = disks
155 .list()
156 .iter()
157 .find(|disk| disk.mount_point() == storage_mountpoint)
158 .context("Cannot find the primary disk. Configuration file might be wrong.")?
159 .available_space() as usize;
160
161 Ok(available_space_b)
162}
163
164pub fn get_drive_name(storage_mountpoint: &PathBuf) -> Result<String> {
166 let disks = Disks::new_with_refreshed_list();
167 let name = disks
168 .list()
169 .iter()
170 .find(|disk| disk.mount_point() == storage_mountpoint)
171 .context("Cannot find the primary disk. Configuration file might be wrong.")?
172 .name()
173 .to_str()
174 .unwrap_or_default()
175 .to_string();
176
177 Ok(name)
178}