use crate::error::WslcError;
use crate::session::WslcSessionHandle;
use std::ffi::CString;
use wslcsdk_sys::types::{WslcVhdRequirements, WslcVhdType};
use wslcsdk_sys::*;
#[derive(Debug, Clone)]
pub struct VhdVolumeOptions<'a> {
pub name: &'a str,
pub size_bytes: u64,
pub vhd_type: WslcVhdType,
pub owner: Option<(u32, u32)>,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct WslcVolumeManager;
impl WslcVolumeManager {
pub fn create_vhd_volume(
session: &WslcSessionHandle,
options: &VhdVolumeOptions<'_>,
) -> Result<(), WslcError> {
if options.name.trim().is_empty() {
return Err(WslcError::InvalidConfiguration(
"卷名称不能为空".to_string(),
));
}
if options.size_bytes == 0 {
return Err(WslcError::InvalidConfiguration(
"卷大小必须大于 0 字节".to_string(),
));
}
let c_name = CString::new(options.name)
.map_err(|e| WslcError::NulError(format!("卷名称含非法空字符: {e}")))?;
let (flags, uid, gid) = match options.owner {
Some((u, g)) => (WSLC_VHD_REQ_FLAG_OWNER, u, g),
None => (WSLC_VHD_REQ_FLAG_NONE, 0, 0),
};
let req = WslcVhdRequirements {
name: c_name.as_ptr(),
size_bytes: options.size_bytes,
vhd_type: options.vhd_type,
flags,
uid,
gid,
};
let mut err_msg: *mut u16 = std::ptr::null_mut();
let hr = unsafe { WslcCreateSessionVhdVolume(session.as_raw(), &req, &mut err_msg) };
unsafe {
WslcError::check(
hr,
err_msg,
format!("创建 VHD 卷失败,名称: '{}'", options.name),
)?;
}
log::info!(
"VHD 卷创建成功,名称: '{}',大小: {} 字节",
options.name,
options.size_bytes
);
Ok(())
}
pub fn delete_vhd_volume(session: &WslcSessionHandle, name: &str) -> Result<(), WslcError> {
if name.trim().is_empty() {
return Err(WslcError::InvalidConfiguration(
"卷名称不能为空".to_string(),
));
}
let c_name = CString::new(name)
.map_err(|e| WslcError::NulError(format!("卷名称含非法空字符: {e}")))?;
let mut err_msg: *mut u16 = std::ptr::null_mut();
let hr =
unsafe { WslcDeleteSessionVhdVolume(session.as_raw(), c_name.as_ptr(), &mut err_msg) };
unsafe {
WslcError::check(hr, err_msg, format!("删除 VHD 卷失败,名称: '{name}'"))?;
}
log::info!("VHD 卷删除成功,名称: '{}'", name);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn fake_session() -> WslcSessionHandle {
unsafe { WslcSessionHandle::from_raw(WslcSession::NULL, "fake-session") }
}
#[test]
fn test_vhd_volume_options_field_access() {
let options = VhdVolumeOptions {
name: "test-volume",
size_bytes: 1024 * 1024,
vhd_type: WslcVhdType::Dynamic,
owner: Some((1000, 1000)),
};
assert_eq!(options.name, "test-volume");
assert_eq!(options.size_bytes, 1024 * 1024);
assert_eq!(options.owner, Some((1000, 1000)));
}
#[test]
fn test_create_rejects_blank_name() {
let session = fake_session();
let options = VhdVolumeOptions {
name: " ",
size_bytes: 1024,
vhd_type: WslcVhdType::Dynamic,
owner: None,
};
assert!(WslcVolumeManager::create_vhd_volume(&session, &options).is_err());
}
#[test]
fn test_create_rejects_zero_size() {
let session = fake_session();
let options = VhdVolumeOptions {
name: "valid-name",
size_bytes: 0,
vhd_type: WslcVhdType::Dynamic,
owner: None,
};
assert!(WslcVolumeManager::create_vhd_volume(&session, &options).is_err());
}
#[test]
fn test_delete_rejects_blank_name() {
let session = fake_session();
assert!(WslcVolumeManager::delete_vhd_volume(&session, "").is_err());
assert!(WslcVolumeManager::delete_vhd_volume(&session, " ").is_err());
}
}