• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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