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
nt_success(status: NTSTATUS) -> bool83 pub fn nt_success(status: NTSTATUS) -> bool {
84 status >= 0
85 }
86
87 impl UNICODE_STRING {
from_ref(slice: &[u16]) -> Self88 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 {
default() -> Self99 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 };
status(&self) -> NTSTATUS118 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
WriteFileEx( hFile: BorrowedHandle<'_>, lpBuffer: *mut ::core::ffi::c_void, nNumberOfBytesToWrite: u32, lpOverlapped: *mut OVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, ) -> BOOL215 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
ReadFileEx( hFile: BorrowedHandle<'_>, lpBuffer: *mut ::core::ffi::c_void, nNumberOfBytesToRead: u32, lpOverlapped: *mut OVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, ) -> BOOL231 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.
recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int248 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 }
send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int251 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 }
recvfrom( socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int, addr: *mut SOCKADDR, addrlen: *mut c_int, ) -> c_int254 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 }
sendto( socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int, addr: *const SOCKADDR, addrlen: c_int, ) -> c_int264 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 }
getaddrinfo( node: *const c_char, service: *const c_char, hints: *const ADDRINFOA, res: *mut *mut ADDRINFOA, ) -> c_int274 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" {
WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32478 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