std\sys\pal\windows/
c.rs

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#![unstable(issue = "none", feature = "windows_c")]
6#![allow(clippy::style)]
7
8use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void};
9use core::ptr;
10
11mod windows_sys;
12pub use windows_sys::*;
13
14pub type WCHAR = u16;
15
16pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _);
17
18// https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170
19pub const EXIT_SUCCESS: u32 = 0;
20pub const EXIT_FAILURE: u32 = 1;
21
22#[cfg(target_vendor = "win7")]
23pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: ptr::null_mut() };
24#[cfg(target_vendor = "win7")]
25pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: ptr::null_mut() };
26#[cfg(not(target_thread_local))]
27pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() };
28
29// Some windows_sys types have different signs than the types we use.
30pub const OBJ_DONT_REPARSE: u32 = windows_sys::OBJ_DONT_REPARSE as u32;
31pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: u32 =
32    windows_sys::FRS_ERR_SYSVOL_POPULATE_TIMEOUT as u32;
33
34// Equivalent to the `NT_SUCCESS` C preprocessor macro.
35// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
36pub fn nt_success(status: NTSTATUS) -> bool {
37    status >= 0
38}
39
40impl UNICODE_STRING {
41    pub fn from_ref(slice: &[u16]) -> Self {
42        let len = size_of_val(slice);
43        Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
44    }
45}
46
47impl OBJECT_ATTRIBUTES {
48    pub fn with_length() -> Self {
49        Self {
50            Length: size_of::<Self>() as _,
51            RootDirectory: ptr::null_mut(),
52            ObjectName: ptr::null_mut(),
53            Attributes: 0,
54            SecurityDescriptor: ptr::null_mut(),
55            SecurityQualityOfService: ptr::null_mut(),
56        }
57    }
58}
59
60impl IO_STATUS_BLOCK {
61    pub const PENDING: Self =
62        IO_STATUS_BLOCK { Anonymous: IO_STATUS_BLOCK_0 { Status: STATUS_PENDING }, Information: 0 };
63    pub fn status(&self) -> NTSTATUS {
64        // SAFETY: If `self.Anonymous.Status` was set then this is obviously safe.
65        // If `self.Anonymous.Pointer` was set then this is the equivalent to converting
66        // the pointer to an integer, which is also safe.
67        // Currently the only safe way to construct `IO_STATUS_BLOCK` outside of
68        // this module is to call the `default` method, which sets the `Status`.
69        unsafe { self.Anonymous.Status }
70    }
71}
72
73/// NB: Use carefully! In general using this as a reference is likely to get the
74/// provenance wrong for the `rest` field!
75#[repr(C)]
76pub struct REPARSE_DATA_BUFFER {
77    pub ReparseTag: c_uint,
78    pub ReparseDataLength: c_ushort,
79    pub Reserved: c_ushort,
80    pub rest: (),
81}
82
83/// NB: Use carefully! In general using this as a reference is likely to get the
84/// provenance wrong for the `PathBuffer` field!
85#[repr(C)]
86pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
87    pub SubstituteNameOffset: c_ushort,
88    pub SubstituteNameLength: c_ushort,
89    pub PrintNameOffset: c_ushort,
90    pub PrintNameLength: c_ushort,
91    pub Flags: c_ulong,
92    pub PathBuffer: WCHAR,
93}
94
95#[repr(C)]
96pub struct MOUNT_POINT_REPARSE_BUFFER {
97    pub SubstituteNameOffset: c_ushort,
98    pub SubstituteNameLength: c_ushort,
99    pub PrintNameOffset: c_ushort,
100    pub PrintNameLength: c_ushort,
101    pub PathBuffer: WCHAR,
102}
103
104// Desktop specific functions & types
105cfg_if::cfg_if! {
106if #[cfg(not(target_vendor = "uwp"))] {
107    pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
108}
109}
110
111// Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
112#[cfg(not(target_vendor = "win7"))]
113#[cfg_attr(
114    target_arch = "x86",
115    link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")
116)]
117#[cfg_attr(not(target_arch = "x86"), link(name = "bcryptprimitives", kind = "raw-dylib"))]
118unsafe extern "system" {
119    pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
120}
121
122windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile(
123    filehandle: *mut HANDLE,
124    desiredaccess: FILE_ACCESS_RIGHTS,
125    objectattributes: *const OBJECT_ATTRIBUTES,
126    iostatusblock: *mut IO_STATUS_BLOCK,
127    shareaccess: FILE_SHARE_MODE,
128    createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
129    createoptions: NTCREATEFILE_CREATE_OPTIONS,
130    namedpipetype: u32,
131    readmode: u32,
132    completionmode: u32,
133    maximuminstances: u32,
134    inboundquota: u32,
135    outboundquota: u32,
136    defaulttimeout: *const u64,
137) -> NTSTATUS);
138
139// Functions that aren't available on every version of Windows that we support,
140// but we still use them and just provide some form of a fallback implementation.
141compat_fn_with_fallback! {
142    pub static KERNEL32: &CStr = c"kernel32";
143
144    // >= Win10 1607
145    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
146    pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT {
147        unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
148    }
149
150    // >= Win10 1607
151    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription
152    pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT {
153        unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
154    }
155
156    // >= Win8 / Server 2012
157    // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
158    #[cfg(target_vendor = "win7")]
159    pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () {
160        unsafe { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) }
161    }
162
163    // >= Win11 / Server 2022
164    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
165    pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
166        unsafe {  GetTempPathW(bufferlength, buffer) }
167    }
168}
169
170#[cfg(not(target_vendor = "win7"))]
171// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library.
172#[cfg_attr(
173    target_arch = "x86",
174    link(
175        name = "api-ms-win-core-synch-l1-2-0",
176        kind = "raw-dylib",
177        import_name_type = "undecorated"
178    )
179)]
180#[cfg_attr(
181    not(target_arch = "x86"),
182    link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
183)]
184unsafe extern "system" {
185    pub fn WaitOnAddress(
186        address: *const c_void,
187        compareaddress: *const c_void,
188        addresssize: usize,
189        dwmilliseconds: u32,
190    ) -> BOOL;
191    pub fn WakeByAddressSingle(address: *const c_void);
192    pub fn WakeByAddressAll(address: *const c_void);
193}
194
195// These are loaded by `load_synch_functions`.
196#[cfg(target_vendor = "win7")]
197compat_fn_optional! {
198    pub fn WaitOnAddress(
199        address: *const c_void,
200        compareaddress: *const c_void,
201        addresssize: usize,
202        dwmilliseconds: u32
203    ) -> BOOL;
204    pub fn WakeByAddressSingle(address: *const c_void);
205}
206
207#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))]
208compat_fn_with_fallback! {
209    pub static NTDLL: &CStr = c"ntdll";
210
211    #[cfg(target_vendor = "win7")]
212    pub fn NtCreateKeyedEvent(
213        KeyedEventHandle: *mut HANDLE,
214        DesiredAccess: u32,
215        ObjectAttributes: *mut c_void,
216        Flags: u32
217    ) -> NTSTATUS {
218        panic!("keyed events not available")
219    }
220    #[cfg(target_vendor = "win7")]
221    pub fn NtReleaseKeyedEvent(
222        EventHandle: HANDLE,
223        Key: *const c_void,
224        Alertable: bool,
225        Timeout: *mut i64
226    ) -> NTSTATUS {
227        panic!("keyed events not available")
228    }
229    #[cfg(target_vendor = "win7")]
230    pub fn NtWaitForKeyedEvent(
231        EventHandle: HANDLE,
232        Key: *const c_void,
233        Alertable: bool,
234        Timeout: *mut i64
235    ) -> NTSTATUS {
236        panic!("keyed events not available")
237    }
238
239    // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically.
240    #[cfg(target_vendor = "uwp")]
241    pub fn NtCreateFile(
242        filehandle: *mut HANDLE,
243        desiredaccess: FILE_ACCESS_RIGHTS,
244        objectattributes: *const OBJECT_ATTRIBUTES,
245        iostatusblock: *mut IO_STATUS_BLOCK,
246        allocationsize: *const i64,
247        fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
248        shareaccess: FILE_SHARE_MODE,
249        createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
250        createoptions: NTCREATEFILE_CREATE_OPTIONS,
251        eabuffer: *const c_void,
252        ealength: u32
253    ) -> NTSTATUS {
254        STATUS_NOT_IMPLEMENTED
255    }
256    #[cfg(target_vendor = "uwp")]
257    pub fn NtOpenFile(
258        filehandle: *mut HANDLE,
259        desiredaccess: u32,
260        objectattributes: *const OBJECT_ATTRIBUTES,
261        iostatusblock: *mut IO_STATUS_BLOCK,
262        shareaccess: u32,
263        openoptions: u32
264    ) -> NTSTATUS {
265        STATUS_NOT_IMPLEMENTED
266    }
267    #[cfg(target_vendor = "uwp")]
268    pub fn NtReadFile(
269        filehandle: HANDLE,
270        event: HANDLE,
271        apcroutine: PIO_APC_ROUTINE,
272        apccontext: *const c_void,
273        iostatusblock: *mut IO_STATUS_BLOCK,
274        buffer: *mut c_void,
275        length: u32,
276        byteoffset: *const i64,
277        key: *const u32
278    ) -> NTSTATUS {
279        STATUS_NOT_IMPLEMENTED
280    }
281    #[cfg(target_vendor = "uwp")]
282    pub fn NtWriteFile(
283        filehandle: HANDLE,
284        event: HANDLE,
285        apcroutine: PIO_APC_ROUTINE,
286        apccontext: *const c_void,
287        iostatusblock: *mut IO_STATUS_BLOCK,
288        buffer: *const c_void,
289        length: u32,
290        byteoffset: *const i64,
291        key: *const u32
292    ) -> NTSTATUS {
293        STATUS_NOT_IMPLEMENTED
294    }
295    #[cfg(target_vendor = "uwp")]
296    pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 {
297        Status as u32
298    }
299}