use thiserror::Error;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
pub mod raw;
#[derive(Debug, Error)]
pub enum DiskError {
#[error("disk I/O")]
Io(#[from] std::io::Error),
#[error("refusing to write to {0}: this looks like the boot disk")]
RefusedBootDisk(String),
#[error("refusing to write to {0}: marked as internal storage")]
RefusedInternal(String),
#[error(
"refusing to write to {device} ({size_gb} GB): exceeds 256 GiB safety threshold. \
Pass --force if you really mean it."
)]
RefusedTooLarge { device: String, size_gb: u64 },
#[error("device path must be /dev/rdiskN, got: {0}")]
BadDevicePath(String),
#[error("DiskArbitration query failed: {0}")]
DaError(String),
#[error("external command failed: {cmd}: {stderr}")]
External { cmd: String, stderr: String },
}
pub type Result<T> = std::result::Result<T, DiskError>;
#[derive(Debug, Clone, Default)]
pub struct SafetyConfig {
pub force: bool,
}
#[derive(Debug, Clone)]
pub struct DeviceInfo {
pub path: String, pub size_bytes: u64,
pub model: String, pub internal: bool,
pub is_boot_disk: bool,
pub removable: bool,
}
impl DeviceInfo {
pub fn check_writable(&self, safety: &SafetyConfig) -> Result<()> {
if self.is_boot_disk {
return Err(DiskError::RefusedBootDisk(self.path.clone()));
}
if self.internal && !safety.force {
return Err(DiskError::RefusedInternal(self.path.clone()));
}
let cap = 256u64 * 1024 * 1024 * 1024;
if self.size_bytes > cap && !safety.force {
return Err(DiskError::RefusedTooLarge {
device: self.path.clone(),
size_gb: self.size_bytes / 1_000_000_000,
});
}
Ok(())
}
}