use crate::*;
use winapi::shared::ntdef::NT_SUCCESS;
use winapi::shared::ntstatus::STATUS_MEDIA_WRITE_PROTECTED;
use winapi::um::winioctl::{
StorageDeviceSeekPenaltyProperty, StorageDeviceTrimProperty, DEVICE_TRIM_DESCRIPTOR, GET_LENGTH_INFORMATION,
IOCTL_DISK_GET_DISK_ATTRIBUTES, IOCTL_DISK_GET_LENGTH_INFO, IOCTL_DISK_IS_WRITABLE, IOCTL_STORAGE_GET_DEVICE_NUMBER,
IOCTL_STORAGE_GET_HOTPLUG_INFO, IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_DEVICE_NUMBER, STORAGE_PROPERTY_QUERY,
};
#[allow(bad_style)]
mod winioctl_ex {
use winapi::shared::minwindef::{DWORD, ULONG};
use winapi::shared::ntdef::{BOOLEAN, ULONGLONG};
use winapi::STRUCT;
STRUCT! { struct STORAGE_HOTPLUG_INFO{
Size: ULONG, MediaRemovable: BOOLEAN, MediaHotplug: BOOLEAN, DeviceHotplug: BOOLEAN, WriteCacheEnableOverride: BOOLEAN, }}
STRUCT! { struct DEVICE_SEEK_PENALTY_DESCRIPTOR {
Version: DWORD,
Size: DWORD,
IncursSeekPenalty: BOOLEAN,
}}
STRUCT! { struct GET_DISK_ATTRIBUTES {
Version: ULONG,
Reserved1: ULONG,
Attributes: ULONGLONG,
}}
}
pub fn length(handle: &Handle) -> Result<u64> {
let mut data = unsafe { StructBuffer::<GET_LENGTH_INFORMATION>::new() };
handle.ioctl_query(IOCTL_DISK_GET_LENGTH_INFO, &mut data)?;
Ok(unsafe { *data.Length.QuadPart() as u64 })
}
pub fn is_readonly(handle: &Handle) -> Result<bool> {
match handle.ioctl_status(IOCTL_DISK_IS_WRITABLE) {
STATUS_MEDIA_WRITE_PROTECTED => Ok(true),
status if NT_SUCCESS(status) => Ok(false), status => Err(Error::from(status)),
}
}
pub fn is_removable(handle: &Handle) -> Result<bool> {
let mut data = unsafe { StructBuffer::<winioctl_ex::STORAGE_HOTPLUG_INFO>::new() };
handle.ioctl_query(IOCTL_STORAGE_GET_HOTPLUG_INFO, &mut data)?;
Ok(data.DeviceHotplug != 0)
}
pub fn device_number(handle: &Handle) -> Result<u32> {
let mut data = unsafe { StructBuffer::<STORAGE_DEVICE_NUMBER>::new() };
handle.ioctl_query(IOCTL_STORAGE_GET_DEVICE_NUMBER, &mut data)?;
Ok(data.DeviceNumber)
}
pub fn is_trim_enabled(handle: &Handle) -> Result<bool> {
let mut input = StructBuffer::<STORAGE_PROPERTY_QUERY>::zeroed();
input.PropertyId = StorageDeviceTrimProperty;
let mut descriptor = unsafe { StructBuffer::<DEVICE_TRIM_DESCRIPTOR>::new() };
handle.ioctl(IOCTL_STORAGE_QUERY_PROPERTY, &input, &mut descriptor)?;
Ok(descriptor.TrimEnabled != 0)
}
pub fn has_seek_penalty(handle: &Handle) -> Result<bool> {
let mut input = StructBuffer::<STORAGE_PROPERTY_QUERY>::zeroed();
input.PropertyId = StorageDeviceSeekPenaltyProperty;
let mut descriptor = unsafe { StructBuffer::<winioctl_ex::DEVICE_SEEK_PENALTY_DESCRIPTOR>::new() };
handle.ioctl(IOCTL_STORAGE_QUERY_PROPERTY, &input, &mut descriptor)?;
Ok(descriptor.IncursSeekPenalty != 0)
}
pub fn attributes(handle: &Handle) -> Result<u64> {
let mut data = unsafe { StructBuffer::<winioctl_ex::GET_DISK_ATTRIBUTES>::new() };
handle.ioctl_query(IOCTL_DISK_GET_DISK_ATTRIBUTES, &mut data)?;
Ok(data.Attributes)
}