Skip to main content

std\sys\io\error/
windows.rs

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