use crate::devices::{format_device_busy_error, DeviceError};
use crate::platform::traits::{DeviceSafety, VolumeOps};
use super::access::PhysicalDriveIoSession;
use super::devices as win_devices;
use super::WindowsPlatform;
pub type WindowsVolumeGuard = PhysicalDriveIoSession;
impl VolumeOps for WindowsPlatform {
type Guard = WindowsVolumeGuard;
fn prepare_for_io(path: &str, auto_unmount: bool) -> Result<Self::Guard, DeviceError> {
let mounts = WindowsPlatform::list_mounts(path)?;
if !mounts.is_empty() && !auto_unmount {
return Err(DeviceError::busy(format_device_busy_error(path, &mounts)));
}
let windows_device = win_devices::canonical_physical_drive_path(path)
.map_err(DeviceError::invalid_path)?;
super::access::prepare_physical_drive_for_write(&windows_device)
.map_err(DeviceError::unmount)
}
fn preflight_for_io(path: &str, auto_unmount: bool) -> Result<(), DeviceError> {
let mounts = WindowsPlatform::list_mounts(path)?;
if mounts.is_empty() {
return Ok(());
}
if !auto_unmount {
return Err(DeviceError::busy(format_device_busy_error(path, &mounts)));
}
Self::unmount_volumes(path)?;
Ok(())
}
fn unmount_volumes(device_path: &str) -> Result<Vec<String>, DeviceError> {
let path = win_devices::canonical_physical_drive_path(device_path)
.map_err(DeviceError::invalid_path)?;
let disk_index = win_devices::parse_physical_drive_index(&path).ok_or_else(|| {
DeviceError::invalid_path(format!("Invalid physical drive path: {device_path}"))
})?;
let targets = win_devices::volume_dismount_targets_for_disk_index(disk_index)
.map_err(DeviceError::query)?;
let mut dismounted = Vec::new();
let mut failures = Vec::new();
for (volume_path, label) in targets {
match super::access::dismount_volume_at_path(&volume_path, &label) {
Ok(()) => dismounted.push(label),
Err(err) => failures.push(err),
}
}
if !failures.is_empty() {
return Err(DeviceError::unmount(format!(
"Could not dismount all volumes on {device_path}: {}",
failures.join("; ")
)));
}
Ok(dismounted)
}
}