#[cfg(target_os = "windows")]
use std::{
ffi::{OsStr, OsString},
fs::canonicalize,
os::windows::ffi::{OsStrExt, OsStringExt},
path::{Path, PathBuf},
};
use thiserror::Error;
#[cfg(target_os = "windows")]
pub fn volume_name_from_mount_point<S: AsRef<OsStr>>(
mount_point: S,
) -> Result<OsString, Win32Error> {
use windows_sys::Win32::{
Foundation::GetLastError, Storage::FileSystem::GetVolumeNameForVolumeMountPointW,
};
const BUFFER_SIZE: u32 = 64;
let mount_point: Vec<u16> = mount_point.as_ref().encode_wide().chain(Some(0)).collect();
let mut buffer = vec![0; BUFFER_SIZE as usize];
unsafe {
if GetVolumeNameForVolumeMountPointW(mount_point.as_ptr(), buffer.as_mut_ptr(), BUFFER_SIZE)
== 0
{
Err(Win32Error { error_code: GetLastError() })
} else {
let length = buffer.iter().position(|&c| c == 0).unwrap();
Ok(OsString::from_wide(&buffer[..length]))
}
}
}
#[cfg(target_os = "windows")]
pub fn get_dos_device_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, Win32Error> {
let path = path.as_ref();
assert!(path.has_root(), "Expected a path with a root");
let root = {
let mut root = OsString::from(path.components().next().unwrap().as_os_str());
root.push(r"\");
root
};
let mut volume_name_root: Vec<u16> =
volume_name_from_mount_point(root)?.encode_wide().collect();
if volume_name_root.starts_with(&[92, 92, 63, 92] ) {
volume_name_root[2] = u16::from(b'.');
}
let mut dos_device_path = PathBuf::from(OsString::from_wide(&volume_name_root));
dos_device_path.extend(path.components().skip(1));
Ok(dos_device_path)
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[error("Win32 Error (GetLastError: {error_code:#X})")]
pub struct Win32Error {
pub error_code: u32,
}
#[cfg(target_os = "windows")]
#[test]
fn test_get_dos_device_path() {
let root = super::fixture_root();
println!("Fixture root: {root:?}");
let dos_device_path = get_dos_device_path(&root).unwrap();
println!("Dos device path: {dos_device_path:?}");
let canonical_dos_device_path = canonicalize(&dos_device_path).unwrap();
println!("-> Canonicalized: {canonical_dos_device_path:?}");
assert_eq!(canonical_dos_device_path, canonicalize(root).unwrap());
}