Files
spacedrive/core/src/volume/classification.rs
T

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);
}