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 OBJECT_ATTRIBUTES {
41    pub fn with_length() -> Self {
42        Self {
43            Length: size_of::<Self>() as _,
44            RootDirectory: ptr::null_mut(),
45            ObjectName: ptr::null_mut(),
46            Attributes: 0,
47            SecurityDescriptor: ptr::null_mut(),
48            SecurityQualityOfService: ptr::null_mut(),
49        }
50    }
51}
52
53impl IO_STATUS_BLOCK {
54    pub const PENDING: Self =
55        IO_STATUS_BLOCK { Anonymous: IO_STATUS_BLOCK_0 { Status: STATUS_PENDING }, Information: 0 };
56    pub fn status(&self) -> NTSTATUS {
57        // SAFETY: If `self.Anonymous.Status` was set then this is obviously safe.
58        // If `self.Anonymous.Pointer` was set then this is the equivalent to converting
59        // the pointer to an integer, which is also safe.
60        // Currently the only safe way to construct `IO_STATUS_BLOCK` outside of
61        // this module is to call the `default` method, which sets the `Status`.
62        unsafe { self.Anonymous.Status }
63    }
64}
65
66/// NB: Use carefully! In general using this as a reference is likely to get the
67/// provenance wrong for the `rest` field!
68#[repr(C)]
69pub struct REPARSE_DATA_BUFFER {
70    pub ReparseTag: c_uint,
71    pub ReparseDataLength: c_ushort,
72    pub Reserved: c_ushort,
73    pub rest: (),
74}
75
76/// NB: Use carefully! In general using this as a reference is likely to get the
77/// provenance wrong for the `PathBuffer` field!
78#[repr(C)]
79pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
80    pub SubstituteNameOffset: c_ushort,
81    pub SubstituteNameLength: c_ushort,
82    pub PrintNameOffset: c_ushort,
83    pub PrintNameLength: c_ushort,
84    pub Flags: c_ulong,
85    pub PathBuffer: WCHAR,
86}
87
88#[repr(C)]
89pub struct MOUNT_POINT_REPARSE_BUFFER {
90    pub SubstituteNameOffset: c_ushort,
91    pub SubstituteNameLength: c_ushort,
92    pub PrintNameOffset: c_ushort,
93    pub PrintNameLength: c_ushort,
94    pub PathBuffer: WCHAR,
95}
96
97// Desktop specific functions & types
98#[cfg(not(target_vendor = "uwp"))]
99pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
100
101// Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
102#[cfg(not(target_vendor = "win7"))]
103#[cfg_attr(
104    target_arch = "x86",
105    link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")
106)]
107#[cfg_attr(not(target_arch = "x86"), link(name = "bcryptprimitives", kind = "raw-dylib"))]
108unsafe extern "system" {
109    pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
110}
111
112windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile(
113    filehandle: *mut HANDLE,
114    desiredaccess: FILE_ACCESS_RIGHTS,
115    objectattributes: *const OBJECT_ATTRIBUTES,
116    iostatusblock: *mut IO_STATUS_BLOCK,
117    shareaccess: FILE_SHARE_MODE,
118    createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
119    createoptions: NTCREATEFILE_CREATE_OPTIONS,
120    namedpipetype: u32,
121    readmode: u32,
122    completionmode: u32,
123    maximuminstances: u32,
124    inboundquota: u32,
125    outboundquota: u32,
126    defaulttimeout: *const u64,
127) -> NTSTATUS);
128
129// Functions that aren't available on every version of Windows that we support,
130// but we still use them and just provide some form of a fallback implementation.
131compat_fn_with_fallback! {
132    pub static KERNEL32: &CStr = c"kernel32";
133
134    // >= Win10 1607
135    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
136    pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT {
137        unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
138    }
139
140    // >= Win10 1607
141    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription
142    pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT {
143        unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
144    }
145
146    // >= Win8 / Server 2012
147    // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
148    #[cfg(target_vendor = "win7")]
149    pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () {
150        unsafe { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) }
151    }
152
153    // >= Win11 / Server 2022
154    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
155    pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
156        unsafe {  GetTempPathW(bufferlength, buffer) }
157    }
158}
159
160#[cfg(not(target_vendor = "win7"))]
161// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library.
162#[cfg_attr(
163    target_arch = "x86",
164    link(
165        name = "api-ms-win-core-synch-l1-2-0",
166        kind = "raw-dylib",
167        import_name_type = "undecorated"
168    )
169)]
170#[cfg_attr(
171    not(target_arch = "x86"),
172    link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
173)]
174unsafe extern "system" {
175    pub fn WaitOnAddress(
176        address: *const c_void,
177        compareaddress: *const c_void,
178        addresssize: usize,
179        dwmilliseconds: u32,
180    ) -> BOOL;
181    pub fn WakeByAddressSingle(address: *const c_void);
182    pub fn WakeByAddressAll(address: *const c_void);
183}
184
185// These are loaded by `load_synch_functions`.
186#[cfg(target_vendor = "win7")]
187compat_fn_optional! {
188    pub fn WaitOnAddress(
189        address: *const c_void,
190        compareaddress: *const c_void,
191        addresssize: usize,
192        dwmilliseconds: u32
193    ) -> BOOL;
194    pub fn WakeByAddressSingle(address: *const c_void);
195}
196
197#[cfg(any(target_vendor = "win7"))]
198compat_fn_with_fallback! {
199    pub static NTDLL: &CStr = c"ntdll";
200
201    #[cfg(target_vendor = "win7")]
202    pub fn NtCreateKeyedEvent(
203        KeyedEventHandle: *mut HANDLE,
204        DesiredAccess: u32,
205        ObjectAttributes: *mut c_void,
206        Flags: u32
207    ) -> NTSTATUS {
208        panic!("keyed events not available")
209    }
210    #[cfg(target_vendor = "win7")]
211    pub fn NtReleaseKeyedEvent(
212        EventHandle: HANDLE,
213        Key: *const c_void,
214        Alertable: bool,
215        Timeout: *mut i64
216    ) -> NTSTATUS {
217        panic!("keyed events not available")
218    }
219    #[cfg(target_vendor = "win7")]
220    pub fn NtWaitForKeyedEvent(
221        EventHandle: HANDLE,
222        Key: *const c_void,
223        Alertable: bool,
224        Timeout: *mut i64
225    ) -> NTSTATUS {
226        panic!("keyed events not available")
227    }
228}
229
230cfg_select! {
231    target_vendor = "uwp" => {
232        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
233        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
234        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
235        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
236        windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
237    }
238    _ => {}
239}