smriti/services/
drive_detector.rs1use serde::{Deserialize, Serialize};
6use std::path::PathBuf;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct DriveInfo {
11 pub name: String,
12 pub path: PathBuf,
13 pub is_removable: bool,
14 pub has_photovault_db: bool,
15 pub total_size_bytes: Option<u64>,
16 pub free_space_bytes: Option<u64>,
17}
18
19pub struct DriveDetector;
21
22impl DriveDetector {
23 pub fn detect() -> Vec<DriveInfo> {
25 let mut drives = Vec::new();
26
27 #[cfg(target_os = "linux")]
28 {
29 for base in &["/media", "/mnt", "/run/media"] {
31 if let Ok(entries) = std::fs::read_dir(base) {
32 for entry in entries.flatten() {
33 if *base == "/media" || base.starts_with("/run/media") {
35 if let Ok(user_entries) = std::fs::read_dir(entry.path()) {
36 for user_entry in user_entries.flatten() {
37 if let Some(drive) = Self::check_path(user_entry.path()) {
38 drives.push(drive);
39 }
40 }
41 }
42 } else if let Some(drive) = Self::check_path(entry.path()) {
43 drives.push(drive);
44 }
45 }
46 }
47 }
48
49 if let Some(home) = dirs::home_dir() {
51 if let Some(drive) = Self::check_path(home.join("Pictures")) {
52 drives.push(drive);
53 }
54 }
55 }
56
57 #[cfg(target_os = "macos")]
58 {
59 if let Ok(entries) = std::fs::read_dir("/Volumes") {
61 for entry in entries.flatten() {
62 if let Some(drive) = Self::check_path(entry.path()) {
63 drives.push(drive);
64 }
65 }
66 }
67 }
68
69 #[cfg(target_os = "windows")]
70 {
71 for letter in 'A'..='Z' {
73 let path = PathBuf::from(format!("{}:\\", letter));
74 if path.exists() {
75 if let Some(drive) = Self::check_path(path) {
76 drives.push(drive);
77 }
78 }
79 }
80 }
81
82 drives
83 }
84
85 pub fn inspect_path(path: PathBuf) -> Option<DriveInfo> {
87 Self::check_path(path)
88 }
89
90 fn check_path(path: PathBuf) -> Option<DriveInfo> {
92 if !path.exists() || !path.is_dir() {
93 return None;
94 }
95
96 if std::fs::read_dir(&path).is_err() {
98 return None;
99 }
100
101 let name = path
102 .file_name()
103 .map(|n| n.to_string_lossy().to_string())
104 .unwrap_or_else(|| path.to_string_lossy().to_string());
105
106 let has_photovault_db = path.join(".photovault").join("photovault.db").exists();
107
108 Some(DriveInfo {
109 name,
110 path,
111 is_removable: true, has_photovault_db,
113 total_size_bytes: None, free_space_bytes: None,
115 })
116 }
117}