Skip to main content

std\sys\io\error/
windows.rs

1use crate::sys::pal::{api, c};
2use crate::{io, ptr};
3
4pub fn errno() -> i32 {
5    api::get_last_error().code as i32
6}
7
8#[inline]
9pub fn is_interrupted(_errno: i32) -> bool {
10    false
11}
12
13pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
14    use io::ErrorKind::*;
15
16    match errno as u32 {
17        c::ERROR_ACCESS_DENIED => return PermissionDenied,
18        c::ERROR_ALREADY_EXISTS => return AlreadyExists,
19        c::ERROR_FILE_EXISTS => return AlreadyExists,
20        c::ERROR_BROKEN_PIPE => return BrokenPipe,
21        c::ERROR_FILE_NOT_FOUND
22        | c::ERROR_PATH_NOT_FOUND
23        | c::ERROR_INVALID_DRIVE
24        | c::ERROR_BAD_NETPATH
25        | c::ERROR_BAD_NET_NAME => return NotFound,
26        c::ERROR_NO_DATA => return BrokenPipe,
27        c::ERROR_INVALID_NAME | c::ERROR_BAD_PATHNAME => return InvalidFilename,
28        c::ERROR_INVALID_PARAMETER => return InvalidInput,
29        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
30        c::ERROR_SEM_TIMEOUT
31        | c::WAIT_TIMEOUT
32        | c::ERROR_DRIVER_CANCEL_TIMEOUT
33        | c::ERROR_OPERATION_ABORTED
34        | c::ERROR_SERVICE_REQUEST_TIMEOUT
35        | c::ERROR_COUNTER_TIMEOUT
36        | c::ERROR_TIMEOUT
37        | c::ERROR_RESOURCE_CALL_TIMED_OUT
38        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
39        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
40        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
41        | c::ERROR_DS_TIMELIMIT_EXCEEDED
42        | c::DNS_ERROR_RECORD_TIMED_OUT
43        | c::ERROR_IPSEC_IKE_TIMED_OUT
44        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
45        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut,
46        c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported,
47        c::ERROR_HOST_UNREACHABLE => return HostUnreachable,
48        c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable,
49        c::ERROR_DIRECTORY => return NotADirectory,
50        c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory,
51        c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty,
52        c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem,
53        c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull,
54        c::ERROR_SEEK_ON_DEVICE => return NotSeekable,
55        c::ERROR_DISK_QUOTA_EXCEEDED => return QuotaExceeded,
56        c::ERROR_FILE_TOO_LARGE => return FileTooLarge,
57        c::ERROR_BUSY => return ResourceBusy,
58        c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
59        c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
60        c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
61        c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
62        c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop,
63        _ => {}
64    }
65
66    match errno {
67        c::WSAEACCES => PermissionDenied,
68        c::WSAEADDRINUSE => AddrInUse,
69        c::WSAEADDRNOTAVAIL => AddrNotAvailable,
70        c::WSAECONNABORTED => ConnectionAborted,
71        c::WSAECONNREFUSED => ConnectionRefused,
72        c::WSAECONNRESET => ConnectionReset,
73        c::WSAEINVAL => InvalidInput,
74        c::WSAENOTCONN => NotConnected,
75        c::WSAEWOULDBLOCK => WouldBlock,
76        c::WSAETIMEDOUT => TimedOut,
77        c::WSAEHOSTUNREACH => HostUnreachable,
78        c::WSAENETDOWN => NetworkDown,
79        c::WSAENETUNREACH => NetworkUnreachable,
80        c::WSAEDQUOT => QuotaExceeded,
81
82        _ => Uncategorized,
83    }
84}
85
86/// Gets a detailed string description for the given error number.
87pub fn error_string(mut errnum: i32) -> String {
88    let mut buf = [0 as c::WCHAR; 2048];
89
90    unsafe {
91        let mut module = ptr::null_mut();
92        let mut flags = 0;
93
94        // NTSTATUS errors may be encoded as HRESULT, which may returned from
95        // GetLastError. For more information about Windows error codes, see
96        // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a
97        if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
98            // format according to https://support.microsoft.com/en-us/help/259693
99            const NTDLL_DLL: &[u16] = &[
100                'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _,
101                'L' as _, 0,
102            ];
103            module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());
104
105            if !module.is_null() {
106                errnum ^= c::FACILITY_NT_BIT as i32;
107                flags = c::FORMAT_MESSAGE_FROM_HMODULE;
108            }
109        }
110
111        let res = c::FormatMessageW(
112            flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS,
113            module,
114            errnum as u32,
115            0,
116            buf.as_mut_ptr(),
117            buf.len() as u32,
118            ptr::null(),
119        ) as usize;
120        if res == 0 {
121            // Sometimes FormatMessageW can fail e.g., system doesn't like 0 as langId,
122            let fm_err = errno();
123            return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})");
124        }
125
126        match String::from_utf16(&buf[..res]) {
127            Ok(mut msg) => {
128                // Trim trailing CRLF inserted by FormatMessageW
129                let len = msg.trim_ascii_end().len();
130                msg.truncate(len);
131                msg
132            }
133            Err(..) => format!(
134                "OS Error {} (FormatMessageW() returned \
135                 invalid UTF-16)",
136                errnum
137            ),
138        }
139    }
140}