xref: /drstd/src/std/sys/windows/c.rs (revision 0fe3ff0054d3aec7fbf9bddecfecb10bc7d23a51)
1 //! C definitions used by libnative that don't belong in liblibc
2 
3 #![allow(nonstandard_style)]
4 #![cfg_attr(test, allow(dead_code))]
5 
6 use crate::std::ffi::CStr;
7 use crate::std::mem;
8 pub use crate::std::os::raw::c_int;
9 use crate::std::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_void};
10 use crate::std::os::windows::io::{AsRawHandle, BorrowedHandle};
11 use crate::std::ptr;
12 use core::ffi::NonZero_c_ulong;
13 
14 mod windows_sys;
15 pub use windows_sys::*;
16 
17 pub type DWORD = c_ulong;
18 pub type NonZeroDWORD = NonZero_c_ulong;
19 pub type LARGE_INTEGER = c_longlong;
20 #[cfg_attr(target_vendor = "uwp", allow(unused))]
21 pub type LONG = c_long;
22 pub type UINT = c_uint;
23 pub type WCHAR = u16;
24 pub type USHORT = c_ushort;
25 pub type SIZE_T = usize;
26 pub type WORD = u16;
27 pub type CHAR = c_char;
28 pub type ULONG = c_ulong;
29 pub type ACCESS_MASK = DWORD;
30 
31 pub type LPCVOID = *const c_void;
32 pub type LPHANDLE = *mut HANDLE;
33 pub type LPOVERLAPPED = *mut OVERLAPPED;
34 pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
35 pub type LPVOID = *mut c_void;
36 pub type LPWCH = *mut WCHAR;
37 pub type LPWSTR = *mut WCHAR;
38 
39 pub type PLARGE_INTEGER = *mut c_longlong;
40 pub type PSRWLOCK = *mut SRWLOCK;
41 
42 pub type socklen_t = c_int;
43 pub type ADDRESS_FAMILY = USHORT;
44 pub use FD_SET as fd_set;
45 pub use LINGER as linger;
46 pub use TIMEVAL as timeval;
47 
48 pub type CONDITION_VARIABLE = RTL_CONDITION_VARIABLE;
49 pub type SRWLOCK = RTL_SRWLOCK;
50 pub type INIT_ONCE = RTL_RUN_ONCE;
51 
52 pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE {
53     Ptr: ptr::null_mut(),
54 };
55 pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK {
56     Ptr: ptr::null_mut(),
57 };
58 pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE {
59     Ptr: ptr::null_mut(),
60 };
61 
62 // Some windows_sys types have different signs than the types we use.
63 pub const OBJ_DONT_REPARSE: u32 = windows_sys::OBJ_DONT_REPARSE as u32;
64 pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: u32 =
65     windows_sys::FRS_ERR_SYSVOL_POPULATE_TIMEOUT as u32;
66 pub const AF_INET: c_int = windows_sys::AF_INET as c_int;
67 pub const AF_INET6: c_int = windows_sys::AF_INET6 as c_int;
68 
69 #[repr(C)]
70 pub struct ip_mreq {
71     pub imr_multiaddr: in_addr,
72     pub imr_interface: in_addr,
73 }
74 
75 #[repr(C)]
76 pub struct ipv6_mreq {
77     pub ipv6mr_multiaddr: in6_addr,
78     pub ipv6mr_interface: c_uint,
79 }
80 
81 // Equivalent to the `NT_SUCCESS` C preprocessor macro.
82 // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
83 pub fn nt_success(status: NTSTATUS) -> bool {
84     status >= 0
85 }
86 
87 impl UNICODE_STRING {
88     pub fn from_ref(slice: &[u16]) -> Self {
89         let len = slice.len() * mem::size_of::<u16>();
90         Self {
91             Length: len as _,
92             MaximumLength: len as _,
93             Buffer: slice.as_ptr() as _,
94         }
95     }
96 }
97 
98 impl Default for OBJECT_ATTRIBUTES {
99     fn default() -> Self {
100         Self {
101             Length: mem::size_of::<Self>() as _,
102             RootDirectory: ptr::null_mut(),
103             ObjectName: ptr::null_mut(),
104             Attributes: 0,
105             SecurityDescriptor: ptr::null_mut(),
106             SecurityQualityOfService: ptr::null_mut(),
107         }
108     }
109 }
110 
111 impl IO_STATUS_BLOCK {
112     pub const PENDING: Self = IO_STATUS_BLOCK {
113         Anonymous: IO_STATUS_BLOCK_0 {
114             Status: STATUS_PENDING,
115         },
116         Information: 0,
117     };
118     pub fn status(&self) -> NTSTATUS {
119         // SAFETY: If `self.Anonymous.Status` was set then this is obviously safe.
120         // If `self.Anonymous.Pointer` was set then this is the equivalent to converting
121         // the pointer to an integer, which is also safe.
122         // Currently the only safe way to construct `IO_STATUS_BLOCK` outside of
123         // this module is to call the `default` method, which sets the `Status`.
124         unsafe { self.Anonymous.Status }
125     }
126 }
127 
128 /// NB: Use carefully! In general using this as a reference is likely to get the
129 /// provenance wrong for the `rest` field!
130 #[repr(C)]
131 pub struct REPARSE_DATA_BUFFER {
132     pub ReparseTag: c_uint,
133     pub ReparseDataLength: c_ushort,
134     pub Reserved: c_ushort,
135     pub rest: (),
136 }
137 
138 /// NB: Use carefully! In general using this as a reference is likely to get the
139 /// provenance wrong for the `PathBuffer` field!
140 #[repr(C)]
141 pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
142     pub SubstituteNameOffset: c_ushort,
143     pub SubstituteNameLength: c_ushort,
144     pub PrintNameOffset: c_ushort,
145     pub PrintNameLength: c_ushort,
146     pub Flags: c_ulong,
147     pub PathBuffer: WCHAR,
148 }
149 
150 #[repr(C)]
151 pub struct MOUNT_POINT_REPARSE_BUFFER {
152     pub SubstituteNameOffset: c_ushort,
153     pub SubstituteNameLength: c_ushort,
154     pub PrintNameOffset: c_ushort,
155     pub PrintNameLength: c_ushort,
156     pub PathBuffer: WCHAR,
157 }
158 #[repr(C)]
159 pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
160     pub ReparseTag: DWORD,
161     pub ReparseDataLength: DWORD,
162     pub Reserved: WORD,
163     pub ReparseTargetLength: WORD,
164     pub ReparseTargetMaximumLength: WORD,
165     pub Reserved1: WORD,
166     pub ReparseTarget: WCHAR,
167 }
168 
169 #[repr(C)]
170 pub struct SOCKADDR_STORAGE_LH {
171     pub ss_family: ADDRESS_FAMILY,
172     pub __ss_pad1: [CHAR; 6],
173     pub __ss_align: i64,
174     pub __ss_pad2: [CHAR; 112],
175 }
176 
177 #[repr(C)]
178 #[derive(Copy, Clone)]
179 pub struct sockaddr_in {
180     pub sin_family: ADDRESS_FAMILY,
181     pub sin_port: USHORT,
182     pub sin_addr: in_addr,
183     pub sin_zero: [CHAR; 8],
184 }
185 
186 #[repr(C)]
187 #[derive(Copy, Clone)]
188 pub struct sockaddr_in6 {
189     pub sin6_family: ADDRESS_FAMILY,
190     pub sin6_port: USHORT,
191     pub sin6_flowinfo: c_ulong,
192     pub sin6_addr: in6_addr,
193     pub sin6_scope_id: c_ulong,
194 }
195 
196 #[repr(C)]
197 #[derive(Copy, Clone)]
198 pub struct in_addr {
199     pub s_addr: u32,
200 }
201 
202 #[repr(C)]
203 #[derive(Copy, Clone)]
204 pub struct in6_addr {
205     pub s6_addr: [u8; 16],
206 }
207 
208 // Desktop specific functions & types
209 cfg_if::cfg_if! {
210 if #[cfg(not(target_vendor = "uwp"))] {
211     pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
212 }
213 }
214 
215 pub unsafe extern "system" fn WriteFileEx(
216     hFile: BorrowedHandle<'_>,
217     lpBuffer: *mut ::core::ffi::c_void,
218     nNumberOfBytesToWrite: u32,
219     lpOverlapped: *mut OVERLAPPED,
220     lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
221 ) -> BOOL {
222     windows_sys::WriteFileEx(
223         hFile.as_raw_handle(),
224         lpBuffer.cast::<u8>(),
225         nNumberOfBytesToWrite,
226         lpOverlapped,
227         lpCompletionRoutine,
228     )
229 }
230 
231 pub unsafe extern "system" fn ReadFileEx(
232     hFile: BorrowedHandle<'_>,
233     lpBuffer: *mut ::core::ffi::c_void,
234     nNumberOfBytesToRead: u32,
235     lpOverlapped: *mut OVERLAPPED,
236     lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
237 ) -> BOOL {
238     windows_sys::ReadFileEx(
239         hFile.as_raw_handle(),
240         lpBuffer,
241         nNumberOfBytesToRead,
242         lpOverlapped,
243         lpCompletionRoutine,
244     )
245 }
246 
247 // POSIX compatibility shims.
248 pub unsafe fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int {
249     windows_sys::recv(socket, buf.cast::<u8>(), len, flags)
250 }
251 pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int {
252     windows_sys::send(socket, buf.cast::<u8>(), len, flags)
253 }
254 pub unsafe fn recvfrom(
255     socket: SOCKET,
256     buf: *mut c_void,
257     len: c_int,
258     flags: c_int,
259     addr: *mut SOCKADDR,
260     addrlen: *mut c_int,
261 ) -> c_int {
262     windows_sys::recvfrom(socket, buf.cast::<u8>(), len, flags, addr, addrlen)
263 }
264 pub unsafe fn sendto(
265     socket: SOCKET,
266     buf: *const c_void,
267     len: c_int,
268     flags: c_int,
269     addr: *const SOCKADDR,
270     addrlen: c_int,
271 ) -> c_int {
272     windows_sys::sendto(socket, buf.cast::<u8>(), len, flags, addr, addrlen)
273 }
274 pub unsafe fn getaddrinfo(
275     node: *const c_char,
276     service: *const c_char,
277     hints: *const ADDRINFOA,
278     res: *mut *mut ADDRINFOA,
279 ) -> c_int {
280     windows_sys::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res)
281 }
282 
283 cfg_if::cfg_if! {
284 if #[cfg(not(target_vendor = "uwp"))] {
285 pub unsafe fn NtReadFile(
286     filehandle: BorrowedHandle<'_>,
287     event: HANDLE,
288     apcroutine: PIO_APC_ROUTINE,
289     apccontext: *mut c_void,
290     iostatusblock: &mut IO_STATUS_BLOCK,
291     buffer: *mut crate::std::mem::MaybeUninit<u8>,
292     length: ULONG,
293     byteoffset: Option<&LARGE_INTEGER>,
294     key: Option<&ULONG>,
295 ) -> NTSTATUS {
296     windows_sys::NtReadFile(
297         filehandle.as_raw_handle(),
298         event,
299         apcroutine,
300         apccontext,
301         iostatusblock,
302         buffer.cast::<c_void>(),
303         length,
304         byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()),
305         key.map(|k| k as *const u32).unwrap_or(ptr::null()),
306     )
307 }
308 pub unsafe fn NtWriteFile(
309     filehandle: BorrowedHandle<'_>,
310     event: HANDLE,
311     apcroutine: PIO_APC_ROUTINE,
312     apccontext: *mut c_void,
313     iostatusblock: &mut IO_STATUS_BLOCK,
314     buffer: *const u8,
315     length: ULONG,
316     byteoffset: Option<&LARGE_INTEGER>,
317     key: Option<&ULONG>,
318 ) -> NTSTATUS {
319     windows_sys::NtWriteFile(
320         filehandle.as_raw_handle(),
321         event,
322         apcroutine,
323         apccontext,
324         iostatusblock,
325         buffer.cast::<c_void>(),
326         length,
327         byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()),
328         key.map(|k| k as *const u32).unwrap_or(ptr::null()),
329     )
330 }
331 }
332 }
333 
334 // Functions that aren't available on every version of Windows that we support,
335 // but we still use them and just provide some form of a fallback implementation.
336 compat_fn_with_fallback! {
337     pub static KERNEL32: &CStr = ansi_str!("kernel32");
338 
339     // >= Win10 1607
340     // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
341     pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT {
342         SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
343     }
344 
345     // >= Win8 / Server 2012
346     // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
347     pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () {
348         GetSystemTimeAsFileTime(lpsystemtimeasfiletime)
349     }
350 
351     // >= Win11 / Server 2022
352     // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
353     pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
354         GetTempPathW(bufferlength, buffer)
355     }
356 }
357 
358 compat_fn_optional! {
359     crate::std::sys::compat::load_synch_functions();
360     pub fn WaitOnAddress(
361         address: *const ::core::ffi::c_void,
362         compareaddress: *const ::core::ffi::c_void,
363         addresssize: usize,
364         dwmilliseconds: u32
365     ) -> BOOL;
366     pub fn WakeByAddressSingle(address: *const ::core::ffi::c_void);
367 }
368 
369 compat_fn_with_fallback! {
370     pub static NTDLL: &CStr = ansi_str!("ntdll");
371 
372     pub fn NtCreateKeyedEvent(
373         KeyedEventHandle: LPHANDLE,
374         DesiredAccess: ACCESS_MASK,
375         ObjectAttributes: LPVOID,
376         Flags: ULONG
377     ) -> NTSTATUS {
378         panic!("keyed events not available")
379     }
380     pub fn NtReleaseKeyedEvent(
381         EventHandle: HANDLE,
382         Key: LPVOID,
383         Alertable: BOOLEAN,
384         Timeout: PLARGE_INTEGER
385     ) -> NTSTATUS {
386         panic!("keyed events not available")
387     }
388     pub fn NtWaitForKeyedEvent(
389         EventHandle: HANDLE,
390         Key: LPVOID,
391         Alertable: BOOLEAN,
392         Timeout: PLARGE_INTEGER
393     ) -> NTSTATUS {
394         panic!("keyed events not available")
395     }
396 
397     // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically.
398     #[cfg(target_vendor = "uwp")]
399     pub fn NtCreateFile(
400         filehandle: *mut HANDLE,
401         desiredaccess: FILE_ACCESS_RIGHTS,
402         objectattributes: *const OBJECT_ATTRIBUTES,
403         iostatusblock: *mut IO_STATUS_BLOCK,
404         allocationsize: *const i64,
405         fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
406         shareaccess: FILE_SHARE_MODE,
407         createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
408         createoptions: NTCREATEFILE_CREATE_OPTIONS,
409         eabuffer: *const ::core::ffi::c_void,
410         ealength: u32
411     ) -> NTSTATUS {
412         STATUS_NOT_IMPLEMENTED
413     }
414     #[cfg(target_vendor = "uwp")]
415     pub fn NtReadFile(
416         filehandle: BorrowedHandle<'_>,
417         event: HANDLE,
418         apcroutine: PIO_APC_ROUTINE,
419         apccontext: *mut c_void,
420         iostatusblock: &mut IO_STATUS_BLOCK,
421         buffer: *mut crate::std::mem::MaybeUninit<u8>,
422         length: ULONG,
423         byteoffset: Option<&LARGE_INTEGER>,
424         key: Option<&ULONG>
425     ) -> NTSTATUS {
426         STATUS_NOT_IMPLEMENTED
427     }
428     #[cfg(target_vendor = "uwp")]
429     pub fn NtWriteFile(
430         filehandle: BorrowedHandle<'_>,
431         event: HANDLE,
432         apcroutine: PIO_APC_ROUTINE,
433         apccontext: *mut c_void,
434         iostatusblock: &mut IO_STATUS_BLOCK,
435         buffer: *const u8,
436         length: ULONG,
437         byteoffset: Option<&LARGE_INTEGER>,
438         key: Option<&ULONG>
439     ) -> NTSTATUS {
440         STATUS_NOT_IMPLEMENTED
441     }
442     #[cfg(target_vendor = "uwp")]
443     pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 {
444         Status as u32
445     }
446 }
447 
448 // # Arm32 shim
449 //
450 // AddVectoredExceptionHandler and WSAStartup use platform-specific types.
451 // However, Microsoft no longer supports thumbv7a so definitions for those targets
452 // are not included in the win32 metadata. We work around that by defining them here.
453 //
454 // Where possible, these definitions should be kept in sync with https://docs.rs/windows-sys
455 cfg_if::cfg_if! {
456 if #[cfg(not(target_vendor = "uwp"))] {
457     #[link(name = "kernel32")]
458     extern "system" {
459         pub fn AddVectoredExceptionHandler(
460             first: u32,
461             handler: PVECTORED_EXCEPTION_HANDLER,
462         ) -> *mut c_void;
463     }
464     pub type PVECTORED_EXCEPTION_HANDLER = Option<
465         unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32,
466     >;
467     #[repr(C)]
468     pub struct EXCEPTION_POINTERS {
469         pub ExceptionRecord: *mut EXCEPTION_RECORD,
470         pub ContextRecord: *mut CONTEXT,
471     }
472     #[cfg(target_arch = "arm")]
473     pub enum CONTEXT {}
474 }}
475 
476 #[link(name = "ws2_32")]
477 extern "system" {
478     pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
479 }
480 #[cfg(target_arch = "arm")]
481 #[repr(C)]
482 pub struct WSADATA {
483     pub wVersion: u16,
484     pub wHighVersion: u16,
485     pub szDescription: [u8; 257],
486     pub szSystemStatus: [u8; 129],
487     pub iMaxSockets: u16,
488     pub iMaxUdpDg: u16,
489     pub lpVendorInfo: PSTR,
490 }
491