use {
crate::windows::volume::{
VolumeKind,
VolumeName,
},
std::{
self,
ptr,
},
windows::{
Win32::{
Foundation::{
ERROR_MORE_DATA,
HANDLE,
},
Storage::FileSystem::{
BusTypeSpaces,
CreateFileW,
FILE_SHARE_READ,
FILE_SHARE_WRITE,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
OPEN_EXISTING,
},
System::{
IO::DeviceIoControl,
Ioctl::{
DISK_EXTENT,
IOCTL_STORAGE_QUERY_PROPERTY,
PropertyStandardQuery,
STORAGE_DEVICE_DESCRIPTOR,
STORAGE_PROPERTY_QUERY,
StorageDeviceProperty,
VOLUME_DISK_EXTENTS,
},
},
},
core::Owned,
},
};
pub fn volume_kind_detect(verbatim_path: &VolumeName) -> VolumeKind {
let handle = match unsafe {
CreateFileW(
verbatim_path.as_pcwstr_no_trailing_backslash(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
None,
OPEN_EXISTING,
Default::default(),
None,
)
} {
Ok(handle) => handle,
Err(_) => return VolumeKind::Unknown,
};
let handle = unsafe { Owned::new(handle) };
let mut extents_buffer = VOLUME_DISK_EXTENTS {
NumberOfDiskExtents: 0,
Extents: [DISK_EXTENT {
DiskNumber: 0,
StartingOffset: 0,
ExtentLength: 0,
}],
};
let mut bytes_returned: u32 = 0;
let result = unsafe {
DeviceIoControl(
*handle,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
None,
0,
Some(&mut extents_buffer as *mut _ as *mut _),
std::mem::size_of::<VOLUME_DISK_EXTENTS>() as u32,
Some(&mut bytes_returned),
None,
)
};
match result {
Ok(_) => match extents_buffer.NumberOfDiskExtents {
1 if is_volume_storage_space(*handle) => VolumeKind::StorageSpace,
1 => VolumeKind::Simple {
disk_number: extents_buffer.Extents[0].DiskNumber,
},
_ => VolumeKind::DynamicDisk,
},
Err(error) if error.code() == ERROR_MORE_DATA.to_hresult() => VolumeKind::DynamicDisk,
Err(_) => VolumeKind::Unknown,
}
}
fn is_volume_storage_space(handle: HANDLE) -> bool {
let query = STORAGE_PROPERTY_QUERY {
PropertyId: StorageDeviceProperty,
QueryType: PropertyStandardQuery,
AdditionalParameters: [0; 1],
};
let mut descriptor = STORAGE_DEVICE_DESCRIPTOR::default();
let result = unsafe {
DeviceIoControl(
handle,
IOCTL_STORAGE_QUERY_PROPERTY,
Some(ptr::addr_of!(query).cast()),
std::mem::size_of::<STORAGE_PROPERTY_QUERY>() as u32,
Some(ptr::addr_of_mut!(descriptor).cast()),
std::mem::size_of::<STORAGE_DEVICE_DESCRIPTOR>() as u32,
None,
None,
)
};
result.is_ok_and(|_| descriptor.BusType == BusTypeSpaces)
}