use crate::error::{Error, Result, wnet_extended_error};
use crate::strings::{from_pwstr, len_u32, to_wide};
use tracing::{debug, trace};
use windows_sys::Win32::Foundation::{ERROR_EXTENDED_ERROR, ERROR_MORE_DATA, NO_ERROR};
use windows_sys::Win32::NetworkManagement::WNet;
fn wide_out(operation: &str, mut call: impl FnMut(*mut u16, *mut u32) -> u32) -> Result<String> {
let mut buf = vec![0u16; 256];
for _ in 0..4 {
let mut len = len_u32(buf.len());
let status = call(buf.as_mut_ptr(), &raw mut len);
debug!("{operation} returned {status}");
match status {
NO_ERROR => return Ok(crate::strings::from_wide_buf(&buf)),
ERROR_MORE_DATA => buf = vec![0u16; len as usize + 1],
ERROR_EXTENDED_ERROR => return Err(wnet_extended_error()),
code => return Err(Error::Windows(code)),
}
}
Err(Error::Windows(ERROR_MORE_DATA))
}
pub fn get_connection(drive: &str) -> Result<String> {
trace!("querying remote share mapped to {drive}");
let device = to_wide(drive)?;
wide_out("WNetGetConnectionW", |buf, len| unsafe {
WNet::WNetGetConnectionW(device.as_ptr(), buf, len)
})
}
pub fn get_user(connection: &str) -> Result<String> {
trace!("querying user for {connection}");
let name = to_wide(connection)?;
let user = wide_out("WNetGetUserW", |buf, len| unsafe {
WNet::WNetGetUserW(name.as_ptr(), buf, len)
})?;
debug!("WNetGetUserW resolved user {user}");
Ok(user)
}
pub fn get_universal_name(local_path: &str) -> Result<String> {
trace!("resolving universal name for mapped path");
let path = to_wide(local_path)?;
let mut buf = vec![0u64; 128];
for _ in 0..4 {
let mut size = len_u32(buf.len() * size_of::<u64>());
let status = unsafe {
WNet::WNetGetUniversalNameW(
path.as_ptr(),
WNet::UNIVERSAL_NAME_INFO_LEVEL,
buf.as_mut_ptr().cast(),
&raw mut size,
)
};
debug!("WNetGetUniversalNameW returned {status}");
match status {
NO_ERROR => {
let name = unsafe {
let info = &*buf.as_ptr().cast::<WNet::UNIVERSAL_NAME_INFOW>();
from_pwstr(info.lpUniversalName)
};
return Ok(name.unwrap_or_default());
}
ERROR_MORE_DATA => buf = vec![0u64; (size as usize).div_ceil(size_of::<u64>())],
ERROR_EXTENDED_ERROR => return Err(wnet_extended_error()),
code => return Err(Error::Windows(code)),
}
}
Err(Error::Windows(ERROR_MORE_DATA))
}