use std::io;
use std::ptr;
use winapi::shared::minwindef::DWORD;
use winapi::shared::winerror::*;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::{
FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS,
};
use winapi::um::winnt::{LANG_SYSTEM_DEFAULT, MAKELANGID, SUBLANG_SYS_DEFAULT, WCHAR};
use crate::{Error, ErrorKind};
pub fn last_os_error() -> Error {
let errno = errno();
let kind = match errno {
ERROR_FILE_NOT_FOUND | ERROR_PATH_NOT_FOUND | ERROR_ACCESS_DENIED => ErrorKind::NoDevice,
_ => ErrorKind::Io(io::ErrorKind::Other),
};
Error::new(kind, error_string(errno).trim())
}
fn errno() -> u32 {
unsafe { GetLastError() }
}
fn error_string(errnum: u32) -> String {
#![allow(non_snake_case)]
let langId = MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) as DWORD;
let mut buf = [0 as WCHAR; 2048];
unsafe {
let res = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
ptr::null_mut(),
errnum as DWORD,
langId as DWORD,
buf.as_mut_ptr(),
buf.len() as DWORD,
ptr::null_mut(),
);
if res == 0 {
let fm_err = errno();
return format!(
"OS Error {} (FormatMessageW() returned error {})",
errnum, fm_err
);
}
let b = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
let msg = String::from_utf16(&buf[..b]);
match msg {
Ok(msg) => msg,
Err(..) => format!(
"OS Error {} (FormatMessageW() returned invalid UTF-16)",
errnum
),
}
}
}