mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-11-03 22:05:11 -05:00
200 lines
5.1 KiB
Rust
200 lines
5.1 KiB
Rust
//! Volume classification system for platform-aware volume type detection
|
|
|
|
use crate::volume::types::{FileSystem, VolumeType};
|
|
use std::path::Path;
|
|
|
|
/// Information needed for volume classification
|
|
#[derive(Debug, Clone)]
|
|
pub struct VolumeDetectionInfo {
|
|
pub mount_point: std::path::PathBuf,
|
|
pub file_system: FileSystem,
|
|
pub total_bytes_capacity: u64,
|
|
pub is_removable: Option<bool>,
|
|
pub is_network_drive: Option<bool>,
|
|
pub device_model: Option<String>,
|
|
}
|
|
|
|
/// Trait for platform-specific volume classification
|
|
pub trait VolumeClassifier {
|
|
fn classify(&self, volume_info: &VolumeDetectionInfo) -> VolumeType;
|
|
}
|
|
|
|
/// macOS volume classifier
|
|
pub struct MacOSClassifier;
|
|
|
|
impl VolumeClassifier for MacOSClassifier {
|
|
fn classify(&self, info: &VolumeDetectionInfo) -> VolumeType {
|
|
let mount_str = info.mount_point.to_string_lossy();
|
|
|
|
match mount_str.as_ref() {
|
|
// Primary system drive (legacy pre-Catalina)
|
|
"/" => VolumeType::Primary,
|
|
|
|
// Primary data volume (modern macOS Catalina+ with APFS system/data split)
|
|
// This is where all user data, applications, and writable files live
|
|
path if path.starts_with("/System/Volumes/Data") => VolumeType::Primary,
|
|
|
|
// System internal volumes (preboot, recovery, VM, etc.)
|
|
path if path.starts_with("/System/Volumes/") => VolumeType::System,
|
|
|
|
// macOS autofs system and /home mount
|
|
path if mount_str.contains("auto_home")
|
|
|| mount_str.as_ref() == "/home"
|
|
|| info.file_system == FileSystem::Other("autofs".to_string()) =>
|
|
{
|
|
VolumeType::System
|
|
}
|
|
|
|
// External drives
|
|
path if path.starts_with("/Volumes/") => {
|
|
if info.is_removable.unwrap_or(false) {
|
|
VolumeType::External
|
|
} else {
|
|
// Could be user-created APFS volume
|
|
VolumeType::Secondary
|
|
}
|
|
}
|
|
|
|
// Network mounts
|
|
path if path.starts_with("/Network/") => VolumeType::Network,
|
|
|
|
_ => VolumeType::Unknown,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Windows volume classifier
|
|
pub struct WindowsClassifier;
|
|
|
|
impl VolumeClassifier for WindowsClassifier {
|
|
fn classify(&self, info: &VolumeDetectionInfo) -> VolumeType {
|
|
let mount_str = info.mount_point.to_string_lossy();
|
|
|
|
match mount_str.as_ref() {
|
|
// Primary system drive (usually C:)
|
|
"C:\\" => VolumeType::Primary,
|
|
|
|
// Recovery and EFI partitions
|
|
path if path.contains("Recovery")
|
|
|| path.contains("EFI")
|
|
|| (info.file_system == FileSystem::FAT32
|
|
&& info.total_bytes_capacity < 1_000_000_000) =>
|
|
{
|
|
VolumeType::System
|
|
}
|
|
|
|
// Other drive letters
|
|
path if path.len() == 3 && path.ends_with(":\\") => {
|
|
if info.is_removable.unwrap_or(false) {
|
|
VolumeType::External
|
|
} else {
|
|
VolumeType::Secondary
|
|
}
|
|
}
|
|
|
|
// Network drives
|
|
path if path.starts_with("\\\\") => VolumeType::Network,
|
|
|
|
_ => VolumeType::Unknown,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Linux volume classifier
|
|
pub struct LinuxClassifier;
|
|
|
|
impl VolumeClassifier for LinuxClassifier {
|
|
fn classify(&self, info: &VolumeDetectionInfo) -> VolumeType {
|
|
let mount_str = info.mount_point.to_string_lossy();
|
|
|
|
match mount_str.as_ref() {
|
|
// Root filesystem
|
|
"/" => VolumeType::Primary,
|
|
|
|
// User data partition
|
|
"/home" => VolumeType::UserData,
|
|
|
|
// System/virtual filesystems
|
|
path if path.starts_with("/proc")
|
|
|| path.starts_with("/sys")
|
|
|| path.starts_with("/dev")
|
|
|| path.starts_with("/boot") =>
|
|
{
|
|
VolumeType::System
|
|
}
|
|
|
|
// External/removable media
|
|
path if path.starts_with("/media/")
|
|
|| path.starts_with("/mnt/")
|
|
|| info.is_removable.unwrap_or(false) =>
|
|
{
|
|
VolumeType::External
|
|
}
|
|
|
|
// Network mounts
|
|
path if info.file_system == FileSystem::Other("nfs".to_string())
|
|
|| info.file_system == FileSystem::Other("cifs".to_string()) =>
|
|
{
|
|
VolumeType::Network
|
|
}
|
|
|
|
_ => VolumeType::Secondary,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// iOS volume classifier
|
|
///
|
|
/// iOS presents unified device storage with no user-accessible separate volumes.
|
|
/// All classification happens during detection - this classifier always returns Primary.
|
|
#[cfg(target_os = "ios")]
|
|
pub struct IosClassifier;
|
|
|
|
#[cfg(target_os = "ios")]
|
|
impl VolumeClassifier for IosClassifier {
|
|
fn classify(&self, _info: &VolumeDetectionInfo) -> VolumeType {
|
|
// iOS only has one volume type - the system volume
|
|
// All classification happens during detection
|
|
VolumeType::Primary
|
|
}
|
|
}
|
|
|
|
/// Fallback classifier for unknown platforms
|
|
pub struct UnknownClassifier;
|
|
|
|
impl VolumeClassifier for UnknownClassifier {
|
|
fn classify(&self, info: &VolumeDetectionInfo) -> VolumeType {
|
|
// Basic classification based on common patterns
|
|
if info.is_removable.unwrap_or(false) {
|
|
VolumeType::External
|
|
} else if info.is_network_drive.unwrap_or(false) {
|
|
VolumeType::Network
|
|
} else {
|
|
VolumeType::Unknown
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Get the appropriate classifier for the current platform
|
|
pub fn get_classifier() -> Box<dyn VolumeClassifier> {
|
|
#[cfg(target_os = "macos")]
|
|
return Box::new(MacOSClassifier);
|
|
|
|
#[cfg(target_os = "windows")]
|
|
return Box::new(WindowsClassifier);
|
|
|
|
#[cfg(target_os = "linux")]
|
|
return Box::new(LinuxClassifier);
|
|
|
|
#[cfg(target_os = "ios")]
|
|
return Box::new(IosClassifier);
|
|
|
|
#[cfg(not(any(
|
|
target_os = "macos",
|
|
target_os = "windows",
|
|
target_os = "linux",
|
|
target_os = "ios"
|
|
)))]
|
|
return Box::new(UnknownClassifier);
|
|
}
|