1 use std::io;
2 use std::ptr;
3
4 use winapi::shared::minwindef::DWORD;
5 use winapi::shared::winerror::*;
6 use winapi::um::errhandlingapi::GetLastError;
7 use winapi::um::winbase::{
8 FormatMessageW, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS,
9 };
10 use winapi::um::winnt::{LANG_SYSTEM_DEFAULT, MAKELANGID, SUBLANG_SYS_DEFAULT, WCHAR};
11
12 use crate::{Error, ErrorKind};
13
last_os_error() -> Error14 pub fn last_os_error() -> Error {
15 let errno = errno();
16
17 let kind = match errno {
18 ERROR_FILE_NOT_FOUND | ERROR_PATH_NOT_FOUND | ERROR_ACCESS_DENIED => ErrorKind::NoDevice,
19 _ => ErrorKind::Io(io::ErrorKind::Other),
20 };
21
22 Error::new(kind, error_string(errno).trim())
23 }
24
25 // the rest of this module is borrowed from libstd
26
errno() -> u3227 fn errno() -> u32 {
28 unsafe { GetLastError() }
29 }
30
error_string(errnum: u32) -> String31 fn error_string(errnum: u32) -> String {
32 #![allow(non_snake_case)]
33
34 // This value is calculated from the macro
35 // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
36 let langId = MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) as DWORD;
37
38 let mut buf = [0 as WCHAR; 2048];
39
40 unsafe {
41 let res = FormatMessageW(
42 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
43 ptr::null_mut(),
44 errnum as DWORD,
45 langId as DWORD,
46 buf.as_mut_ptr(),
47 buf.len() as DWORD,
48 ptr::null_mut(),
49 );
50 if res == 0 {
51 // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
52 let fm_err = errno();
53 return format!(
54 "OS Error {} (FormatMessageW() returned error {})",
55 errnum, fm_err
56 );
57 }
58
59 let b = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
60 let msg = String::from_utf16(&buf[..b]);
61 match msg {
62 Ok(msg) => msg,
63 Err(..) => format!(
64 "OS Error {} (FormatMessageW() returned invalid UTF-16)",
65 errnum
66 ),
67 }
68 }
69 }
70