std\sys\pal\windows/api.rs
1//! # Safe(r) wrappers around Windows API functions.
2//!
3//! This module contains fairly thin wrappers around Windows API functions,
4//! aimed at centralising safety instead of having unsafe blocks spread
5//! throughout higher level code. This makes it much easier to audit FFI safety.
6//!
7//! Not all functions can be made completely safe without more context but in
8//! such cases we should still endeavour to reduce the caller's burden of safety
9//! as much as possible.
10//!
11//! ## Guidelines for wrappers
12//!
13//! Items here should be named similarly to their raw Windows API name, except
14//! that they follow Rust's case conventions. E.g. function names are
15//! lower_snake_case. The idea here is that it should be easy for a Windows
16//! C/C++ programmer to identify the underlying function that's being wrapped
17//! while not looking too out of place in Rust code.
18//!
19//! Every use of an `unsafe` block must have a related SAFETY comment, even if
20//! it's trivially safe (for example, see `get_last_error`). Public unsafe
21//! functions must document what the caller has to do to call them safely.
22//!
23//! Avoid unchecked `as` casts. For integers, either assert that the integer
24//! is in range or use `try_into` instead. For pointers, prefer to use
25//! `ptr.cast::<Type>()` when possible.
26//!
27//! This module must only depend on core and not on std types as the eventual
28//! hope is to have std depend on sys and not the other way around.
29//! However, some amount of glue code may currently be necessary so such code
30//! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example.
31
32use core::ffi::c_void;
33
34use super::c;
35
36/// Creates a null-terminated UTF-16 string from a str.
37pub macro wide_str($str:literal) {{
38 const _: () = {
39 if core::slice::memchr::memchr(0, $str.as_bytes()).is_some() {
40 panic!("null terminated strings cannot contain interior nulls");
41 }
42 };
43 crate::sys::pal::windows::api::utf16!(concat!($str, '\0'))
44}}
45
46/// Creates a UTF-16 string from a str without null termination.
47pub macro utf16($str:expr) {{
48 const UTF8: &str = $str;
49 const UTF16_LEN: usize = crate::sys::pal::windows::api::utf16_len(UTF8);
50 const UTF16: [u16; UTF16_LEN] = crate::sys::pal::windows::api::to_utf16(UTF8);
51 &UTF16
52}}
53
54#[cfg(test)]
55mod tests;
56
57/// Gets the UTF-16 length of a UTF-8 string, for use in the wide_str macro.
58pub const fn utf16_len(s: &str) -> usize {
59 let s = s.as_bytes();
60 let mut i = 0;
61 let mut len = 0;
62 while i < s.len() {
63 // the length of a UTF-8 encoded code-point is given by the number of
64 // leading ones, except in the case of ASCII.
65 let utf8_len = match s[i].leading_ones() {
66 0 => 1,
67 n => n as usize,
68 };
69 i += utf8_len;
70 // Note that UTF-16 surrogates (U+D800 to U+DFFF) are not encodable as UTF-8,
71 // so (unlike with WTF-8) we don't have to worry about how they'll get re-encoded.
72 len += if utf8_len < 4 { 1 } else { 2 };
73 }
74 len
75}
76
77/// Const convert UTF-8 to UTF-16, for use in the wide_str macro.
78///
79/// Note that this is designed for use in const contexts so is not optimized.
80pub const fn to_utf16<const UTF16_LEN: usize>(s: &str) -> [u16; UTF16_LEN] {
81 let mut output = [0_u16; UTF16_LEN];
82 let mut pos = 0;
83 let s = s.as_bytes();
84 let mut i = 0;
85 while i < s.len() {
86 match s[i].leading_ones() {
87 // Decode UTF-8 based on its length.
88 // See https://en.wikipedia.org/wiki/UTF-8
89 0 => {
90 // ASCII is the same in both encodings
91 output[pos] = s[i] as u16;
92 i += 1;
93 pos += 1;
94 }
95 2 => {
96 // Bits: 110xxxxx 10xxxxxx
97 output[pos] = ((s[i] as u16 & 0b11111) << 6) | (s[i + 1] as u16 & 0b111111);
98 i += 2;
99 pos += 1;
100 }
101 3 => {
102 // Bits: 1110xxxx 10xxxxxx 10xxxxxx
103 output[pos] = ((s[i] as u16 & 0b1111) << 12)
104 | ((s[i + 1] as u16 & 0b111111) << 6)
105 | (s[i + 2] as u16 & 0b111111);
106 i += 3;
107 pos += 1;
108 }
109 4 => {
110 // Bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111 let mut c = ((s[i] as u32 & 0b111) << 18)
112 | ((s[i + 1] as u32 & 0b111111) << 12)
113 | ((s[i + 2] as u32 & 0b111111) << 6)
114 | (s[i + 3] as u32 & 0b111111);
115 // re-encode as UTF-16 (see https://en.wikipedia.org/wiki/UTF-16)
116 // - Subtract 0x10000 from the code point
117 // - For the high surrogate, shift right by 10 then add 0xD800
118 // - For the low surrogate, take the low 10 bits then add 0xDC00
119 c -= 0x10000;
120 output[pos] = ((c >> 10) + 0xD800) as u16;
121 output[pos + 1] = ((c & 0b1111111111) + 0xDC00) as u16;
122 i += 4;
123 pos += 2;
124 }
125 // valid UTF-8 cannot have any other values
126 _ => unreachable!(),
127 }
128 }
129 output
130}
131
132/// Helper method for getting the size of `T` as a u32.
133/// Errors at compile time if the size would overflow.
134///
135/// While a type larger than u32::MAX is unlikely, it is possible if only because of a bug.
136/// However, one key motivation for this function is to avoid the temptation to
137/// use frequent `as` casts. This is risky because they are too powerful.
138/// For example, the following will compile today:
139///
140/// `size_of::<u64> as u32`
141///
142/// Note that `size_of` is never actually called, instead a function pointer is
143/// converted to a `u32`. Clippy would warn about this but, alas, it's not run
144/// on the standard library.
145const fn win32_size_of<T: Sized>() -> u32 {
146 // Const assert that the size does not exceed u32::MAX.
147 // Uses a trait to workaround restriction on using generic types in inner items.
148 trait Win32SizeOf: Sized {
149 const WIN32_SIZE_OF: u32 = {
150 let size = size_of::<Self>();
151 assert!(size <= u32::MAX as usize);
152 size as u32
153 };
154 }
155 impl<T: Sized> Win32SizeOf for T {}
156
157 T::WIN32_SIZE_OF
158}
159
160/// The `SetFileInformationByHandle` function takes a generic parameter by
161/// making the user specify the type (class), a pointer to the data and its
162/// size. This trait allows attaching that information to a Rust type so that
163/// [`set_file_information_by_handle`] can be called safely.
164///
165/// This trait is designed so that it can support variable sized types.
166/// However, currently Rust's std only uses fixed sized structures.
167///
168/// # Safety
169///
170/// * `as_ptr` must return a pointer to memory that is readable up to `size` bytes.
171/// * `CLASS` must accurately reflect the type pointed to by `as_ptr`. E.g.
172/// the `FILE_BASIC_INFO` structure has the class `FileBasicInfo`.
173pub unsafe trait SetFileInformation {
174 /// The type of information to set.
175 const CLASS: i32;
176 /// A pointer to the file information to set.
177 fn as_ptr(&self) -> *const c_void;
178 /// The size of the type pointed to by `as_ptr`.
179 fn size(&self) -> u32;
180}
181/// Helper trait for implementing `SetFileInformation` for statically sized types.
182unsafe trait SizedSetFileInformation: Sized {
183 const CLASS: i32;
184}
185unsafe impl<T: SizedSetFileInformation> SetFileInformation for T {
186 const CLASS: i32 = T::CLASS;
187 fn as_ptr(&self) -> *const c_void {
188 (&raw const *self).cast::<c_void>()
189 }
190 fn size(&self) -> u32 {
191 win32_size_of::<Self>()
192 }
193}
194
195// SAFETY: FILE_BASIC_INFO, FILE_END_OF_FILE_INFO, FILE_ALLOCATION_INFO,
196// FILE_DISPOSITION_INFO, FILE_DISPOSITION_INFO_EX and FILE_IO_PRIORITY_HINT_INFO
197// are all plain `repr(C)` structs that only contain primitive types.
198// The given information classes correctly match with the struct.
199unsafe impl SizedSetFileInformation for c::FILE_BASIC_INFO {
200 const CLASS: i32 = c::FileBasicInfo;
201}
202unsafe impl SizedSetFileInformation for c::FILE_END_OF_FILE_INFO {
203 const CLASS: i32 = c::FileEndOfFileInfo;
204}
205unsafe impl SizedSetFileInformation for c::FILE_ALLOCATION_INFO {
206 const CLASS: i32 = c::FileAllocationInfo;
207}
208unsafe impl SizedSetFileInformation for c::FILE_DISPOSITION_INFO {
209 const CLASS: i32 = c::FileDispositionInfo;
210}
211unsafe impl SizedSetFileInformation for c::FILE_DISPOSITION_INFO_EX {
212 const CLASS: i32 = c::FileDispositionInfoEx;
213}
214unsafe impl SizedSetFileInformation for c::FILE_IO_PRIORITY_HINT_INFO {
215 const CLASS: i32 = c::FileIoPriorityHintInfo;
216}
217
218#[inline]
219pub fn set_file_information_by_handle<T: SetFileInformation>(
220 handle: c::HANDLE,
221 info: &T,
222) -> Result<(), WinError> {
223 unsafe fn set_info(
224 handle: c::HANDLE,
225 class: i32,
226 info: *const c_void,
227 size: u32,
228 ) -> Result<(), WinError> {
229 unsafe {
230 let result = c::SetFileInformationByHandle(handle, class, info, size);
231 (result != 0).then_some(()).ok_or_else(get_last_error)
232 }
233 }
234 // SAFETY: The `SetFileInformation` trait ensures that this is safe.
235 unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) }
236}
237
238/// Gets the error from the last function.
239/// This must be called immediately after the function that sets the error to
240/// avoid the risk of another function overwriting it.
241pub fn get_last_error() -> WinError {
242 // SAFETY: This just returns a thread-local u32 and has no other effects.
243 unsafe { WinError { code: c::GetLastError() } }
244}
245
246/// An error code as returned by [`get_last_error`].
247///
248/// This is usually a 16-bit Win32 error code but may be a 32-bit HRESULT or NTSTATUS.
249/// Check the documentation of the Windows API function being called for expected errors.
250#[derive(Clone, Copy, PartialEq, Eq)]
251#[repr(transparent)]
252pub struct WinError {
253 pub code: u32,
254}
255impl WinError {
256 pub const fn new(code: u32) -> Self {
257 Self { code }
258 }
259}
260
261// Error code constants.
262// The constant names should be the same as the winapi constants except for the leading `ERROR_`.
263// Due to the sheer number of codes, error codes should only be added here on an as-needed basis.
264// However, they should never be removed as the assumption is they may be useful again in the future.
265#[allow(unused)]
266impl WinError {
267 /// Success is not an error.
268 /// Some Windows APIs do use this to distinguish between a zero return and an error return
269 /// but we should never return this to users as an error.
270 pub const SUCCESS: Self = Self::new(c::ERROR_SUCCESS);
271 // tidy-alphabetical-start
272 pub const ACCESS_DENIED: Self = Self::new(c::ERROR_ACCESS_DENIED);
273 pub const ALREADY_EXISTS: Self = Self::new(c::ERROR_ALREADY_EXISTS);
274 pub const BAD_NET_NAME: Self = Self::new(c::ERROR_BAD_NET_NAME);
275 pub const BAD_NETPATH: Self = Self::new(c::ERROR_BAD_NETPATH);
276 pub const CANT_ACCESS_FILE: Self = Self::new(c::ERROR_CANT_ACCESS_FILE);
277 pub const DELETE_PENDING: Self = Self::new(c::ERROR_DELETE_PENDING);
278 pub const DIR_NOT_EMPTY: Self = Self::new(c::ERROR_DIR_NOT_EMPTY);
279 pub const DIRECTORY: Self = Self::new(c::ERROR_DIRECTORY);
280 pub const FILE_NOT_FOUND: Self = Self::new(c::ERROR_FILE_NOT_FOUND);
281 pub const INSUFFICIENT_BUFFER: Self = Self::new(c::ERROR_INSUFFICIENT_BUFFER);
282 pub const INVALID_FUNCTION: Self = Self::new(c::ERROR_INVALID_FUNCTION);
283 pub const INVALID_HANDLE: Self = Self::new(c::ERROR_INVALID_HANDLE);
284 pub const INVALID_PARAMETER: Self = Self::new(c::ERROR_INVALID_PARAMETER);
285 pub const NO_MORE_FILES: Self = Self::new(c::ERROR_NO_MORE_FILES);
286 pub const NOT_FOUND: Self = Self::new(c::ERROR_NOT_FOUND);
287 pub const NOT_SUPPORTED: Self = Self::new(c::ERROR_NOT_SUPPORTED);
288 pub const OPERATION_ABORTED: Self = Self::new(c::ERROR_OPERATION_ABORTED);
289 pub const PATH_NOT_FOUND: Self = Self::new(c::ERROR_PATH_NOT_FOUND);
290 pub const SHARING_VIOLATION: Self = Self::new(c::ERROR_SHARING_VIOLATION);
291 pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT);
292 // tidy-alphabetical-end
293}