pal/
windows.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![cfg(windows)]
5// UNSAFETY: Calls to Win32 functions to handle delay loading, interacting
6// with low level primitives, and memory management.
7#![expect(unsafe_code)]
8#![expect(clippy::undocumented_unsafe_blocks, clippy::missing_safety_doc)]
9
10pub mod afd;
11pub mod alpc;
12pub mod fs;
13pub mod job;
14pub mod pipe;
15pub mod process;
16pub mod security;
17pub mod tp;
18
19use self::security::SecurityDescriptor;
20use handleapi::INVALID_HANDLE_VALUE;
21use ntapi::ntioapi::FILE_COMPLETION_INFORMATION;
22use ntapi::ntioapi::FileReplaceCompletionInformation;
23use ntapi::ntioapi::IO_STATUS_BLOCK;
24use ntapi::ntioapi::NtAssociateWaitCompletionPacket;
25use ntapi::ntioapi::NtCancelWaitCompletionPacket;
26use ntapi::ntioapi::NtCreateWaitCompletionPacket;
27use ntapi::ntioapi::NtSetInformationFile;
28use ntapi::ntobapi::NtCreateDirectoryObject;
29use ntapi::ntobapi::NtOpenDirectoryObject;
30use ntapi::ntrtl;
31use ntdef::ANSI_STRING;
32use ntdef::UNICODE_STRING;
33use ntrtl::RtlAllocateHeap;
34use ntrtl::RtlDosPathNameToNtPathName_U_WithStatus;
35use ntrtl::RtlFreeUnicodeString;
36use ntrtl::RtlNtStatusToDosErrorNoTeb;
37use processthreadsapi::GetExitCodeProcess;
38use std::cell::UnsafeCell;
39use std::ffi::OsStr;
40use std::ffi::c_void;
41use std::fs::File;
42use std::io;
43use std::io::Error;
44use std::io::Result;
45use std::marker::PhantomData;
46use std::mem::zeroed;
47use std::os::windows::prelude::*;
48use std::path::Path;
49use std::ptr::NonNull;
50use std::ptr::addr_of;
51use std::ptr::null_mut;
52use std::sync::Once;
53use std::sync::atomic::AtomicUsize;
54use std::sync::atomic::Ordering;
55use std::time::Duration;
56use widestring::U16CString;
57use widestring::Utf16Str;
58use winapi::shared::ntdef;
59use winapi::shared::ntdef::NTSTATUS;
60use winapi::shared::ntstatus;
61use winapi::shared::ntstatus::STATUS_PENDING;
62use winapi::shared::winerror::ERROR_BAD_PATHNAME;
63use winapi::shared::ws2def;
64use winapi::um::errhandlingapi::GetErrorMode;
65use winapi::um::errhandlingapi::SetErrorMode;
66use winapi::um::handleapi;
67use winapi::um::handleapi::CloseHandle;
68use winapi::um::heapapi::GetProcessHeap;
69use winapi::um::ioapiset::CreateIoCompletionPort;
70use winapi::um::ioapiset::GetQueuedCompletionStatusEx;
71use winapi::um::ioapiset::PostQueuedCompletionStatus;
72use winapi::um::minwinbase::OVERLAPPED;
73use winapi::um::minwinbase::OVERLAPPED_ENTRY;
74use winapi::um::processenv::SetStdHandle;
75use winapi::um::processthreadsapi;
76use winapi::um::processthreadsapi::TerminateProcess;
77use winapi::um::synchapi;
78use winapi::um::winbase::INFINITE;
79use winapi::um::winbase::SEM_FAILCRITICALERRORS;
80use winapi::um::winbase::STD_OUTPUT_HANDLE;
81use winapi::um::winbase::SetFileCompletionNotificationModes;
82use winapi::um::winnt;
83use winapi::um::winsock2;
84
85#[repr(transparent)]
86#[derive(Debug, Copy, Clone, PartialEq, Eq)]
87pub struct SendSyncRawHandle(pub RawHandle);
88
89unsafe impl Send for SendSyncRawHandle {}
90unsafe impl Sync for SendSyncRawHandle {}
91
92pub trait BorrowedHandleExt: Sized {
93    fn duplicate(&self, inherit: bool, access: Option<u32>) -> Result<OwnedHandle>;
94}
95
96impl BorrowedHandleExt for BorrowedHandle<'_> {
97    fn duplicate(&self, inherit: bool, access: Option<u32>) -> Result<OwnedHandle> {
98        let mut handle = null_mut();
99        let options = if access.is_some() {
100            0
101        } else {
102            winnt::DUPLICATE_SAME_ACCESS
103        };
104        unsafe {
105            let process = processthreadsapi::GetCurrentProcess();
106            if handleapi::DuplicateHandle(
107                process,
108                self.as_raw_handle(),
109                process,
110                &mut handle,
111                access.unwrap_or(0),
112                inherit.into(),
113                options,
114            ) == 0
115            {
116                return Err(Error::last_os_error());
117            }
118            Ok(OwnedHandle::from_raw_handle(handle))
119        }
120    }
121}
122
123pub trait OwnedSocketExt: Sized {
124    /// Prepares the socket for being sent to another process.
125    ///
126    /// After calling this, the socket should not be used for anything other
127    /// than duplicating to a handle (which can then be converted back to a
128    /// socket with `from_handle`).
129    fn prepare_to_send(&mut self) -> Result<BorrowedHandle<'_>>;
130
131    /// Converts a handle, originally duplicated from another socket, to a
132    /// socket. The original socket should have been prepared with
133    /// [`Self::prepare_to_send`].
134    fn from_handle(handle: OwnedHandle) -> Result<Self>;
135}
136
137const SIO_SOCKET_TRANSFER_BEGIN: u32 = ws2def::IOC_IN | ws2def::IOC_VENDOR | 301;
138const SIO_SOCKET_TRANSFER_END: u32 = ws2def::IOC_IN | ws2def::IOC_VENDOR | 302;
139
140/// Ensures WSAStartup has been called for the process.
141fn init_winsock() {
142    static INIT: Once = Once::new();
143
144    INIT.call_once(|| {
145        // Initialize a dummy socket, then throw away the result, to get the
146        // socket library to call WSAStartup for us.
147        let _ = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::DGRAM, None);
148    });
149}
150
151impl OwnedSocketExt for OwnedSocket {
152    fn prepare_to_send(&mut self) -> Result<BorrowedHandle<'_>> {
153        let mut catalog_id: u32 = 0;
154        let mut bytes = 0;
155        // SAFETY: calling the ioctl according to implementation requirements
156        unsafe {
157            if winsock2::WSAIoctl(
158                self.as_raw_socket() as _,
159                SIO_SOCKET_TRANSFER_BEGIN,
160                null_mut(),
161                0,
162                std::ptr::from_mut(&mut catalog_id).cast(),
163                size_of_val(&catalog_id) as u32,
164                &mut bytes,
165                null_mut(),
166                None,
167            ) != 0
168            {
169                return Err(Error::from_raw_os_error(winsock2::WSAGetLastError()));
170            }
171            Ok(BorrowedHandle::borrow_raw(self.as_raw_socket() as RawHandle))
172        }
173    }
174
175    fn from_handle(handle: OwnedHandle) -> Result<Self> {
176        // This could be the first winsock interaction for the process.
177        init_winsock();
178
179        let mut catalog_id: u32 = 0;
180        let mut bytes = 0;
181        let mut socket = handle.as_raw_handle() as winsock2::SOCKET;
182        // SAFETY: calling the ioctl according to implementation requirements
183        unsafe {
184            if winsock2::WSAIoctl(
185                socket,
186                SIO_SOCKET_TRANSFER_END,
187                std::ptr::from_mut(&mut catalog_id).cast(),
188                size_of_val(&catalog_id) as u32,
189                std::ptr::from_mut(&mut socket).cast(),
190                size_of_val(&socket) as u32,
191                &mut bytes,
192                null_mut(),
193                None,
194            ) != 0
195            {
196                return Err(Error::from_raw_os_error(winsock2::WSAGetLastError()));
197            }
198            // In theory SIO_SOCKET_TRANSFER_END could have changed `socket`, so
199            // forget the handle and use the socket instead.
200            let _gone = handle.into_raw_handle();
201            Ok(Self::from_raw_socket(socket as RawSocket))
202        }
203    }
204}
205
206#[repr(transparent)]
207#[derive(Debug)]
208struct WaitObject(OwnedHandle);
209
210impl WaitObject {
211    fn wait(&self) {
212        assert!(unsafe { synchapi::WaitForSingleObject(self.0.as_raw_handle(), INFINITE) } == 0);
213    }
214}
215
216impl Clone for WaitObject {
217    fn clone(&self) -> Self {
218        Self(
219            self.0
220                .try_clone()
221                .expect("out of resources cloning wait object"),
222        )
223    }
224}
225
226#[derive(Debug, Clone)]
227pub struct Process(WaitObject);
228
229impl Process {
230    pub fn wait(&self) {
231        self.0.wait()
232    }
233
234    pub fn id(&self) -> u32 {
235        unsafe {
236            let pid = processthreadsapi::GetProcessId(self.as_handle().as_raw_handle());
237            assert_ne!(pid, 0);
238            pid
239        }
240    }
241
242    pub fn exit_code(&self) -> u32 {
243        let mut code = 0;
244        unsafe {
245            assert!(GetExitCodeProcess(self.as_handle().as_raw_handle(), &mut code) != 0);
246        }
247        code
248    }
249
250    /// Terminates the process immediately, setting its exit code to `exit_code`.
251    pub fn kill(&self, exit_code: u32) -> Result<()> {
252        // SAFETY: calling TerminateProcess according to API docs.
253        unsafe {
254            if TerminateProcess(self.as_handle().as_raw_handle(), exit_code) == 0 {
255                return Err(Error::last_os_error());
256            }
257        }
258        Ok(())
259    }
260}
261
262impl From<OwnedHandle> for Process {
263    fn from(handle: OwnedHandle) -> Self {
264        Self(WaitObject(handle))
265    }
266}
267
268impl AsHandle for Process {
269    fn as_handle(&self) -> BorrowedHandle<'_> {
270        (self.0).0.as_handle()
271    }
272}
273
274impl From<Process> for OwnedHandle {
275    fn from(value: Process) -> OwnedHandle {
276        (value.0).0
277    }
278}
279
280#[derive(Debug)]
281pub struct IoCompletionPort(OwnedHandle);
282
283impl IoCompletionPort {
284    pub fn new() -> Self {
285        unsafe {
286            let handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, null_mut(), 0, 0);
287            if handle.is_null() {
288                panic!("oom allocating completion port");
289            }
290            Self(OwnedHandle::from_raw_handle(handle))
291        }
292    }
293
294    pub fn get(&self, entries: &mut [OVERLAPPED_ENTRY], timeout: Option<Duration>) -> usize {
295        unsafe {
296            let mut n = 0;
297            if GetQueuedCompletionStatusEx(
298                self.0.as_raw_handle(),
299                entries.as_mut_ptr(),
300                entries.len().try_into().expect("too many entries"),
301                &mut n,
302                timeout
303                    .map(|t| t.as_millis().try_into().unwrap_or(INFINITE - 1))
304                    .unwrap_or(INFINITE),
305                false.into(),
306            ) != 0
307            {
308                n as usize
309            } else {
310                // TODO: assert timeout
311                assert!(timeout.is_some());
312                0
313            }
314        }
315    }
316
317    // Per MSDN, overlapped values are not dereferenced by PostQueuedCompletionStatus,
318    // they are passed as-is to the caller of GetQueuedCompletionStatus.
319    #[expect(clippy::not_unsafe_ptr_arg_deref)]
320    pub fn post(&self, bytes: u32, key: usize, overlapped: *mut OVERLAPPED) {
321        unsafe {
322            if PostQueuedCompletionStatus(self.0.as_raw_handle(), bytes, key, overlapped) == 0 {
323                panic!("oom posting completion port");
324            }
325        }
326    }
327
328    /// # Safety
329    ///
330    /// The caller must ensure that `handle` is valid.
331    pub unsafe fn associate(&self, handle: RawHandle, key: usize) -> Result<()> {
332        if unsafe { CreateIoCompletionPort(handle, self.0.as_raw_handle(), key, 0).is_null() } {
333            return Err(Error::last_os_error());
334        }
335        Ok(())
336    }
337}
338
339impl From<OwnedHandle> for IoCompletionPort {
340    fn from(handle: OwnedHandle) -> Self {
341        Self(handle)
342    }
343}
344
345impl AsHandle for IoCompletionPort {
346    fn as_handle(&self) -> BorrowedHandle<'_> {
347        self.0.as_handle()
348    }
349}
350
351impl From<IoCompletionPort> for OwnedHandle {
352    fn from(value: IoCompletionPort) -> OwnedHandle {
353        value.0
354    }
355}
356
357/// Sets file completion notification modes for `handle`.
358///
359/// # Safety
360/// The caller must ensure that `handle` is valid and that changing the
361/// notification modes does not cause a safety issue elsewhere (e.g. by causing
362/// unexpected IO completions in a completion port).
363pub unsafe fn set_file_completion_notification_modes(handle: RawHandle, flags: u8) -> Result<()> {
364    // SAFETY: caller guarantees contract.
365    if unsafe { SetFileCompletionNotificationModes(handle, flags) } == 0 {
366        return Err(Error::last_os_error());
367    }
368    Ok(())
369}
370
371/// Disassociates `handle` from its completion port.
372///
373/// # Safety
374///
375/// The caller must ensure that `handle` is valid.
376pub unsafe fn disassociate_completion_port(handle: RawHandle) -> Result<()> {
377    let mut info = FILE_COMPLETION_INFORMATION {
378        Port: null_mut(),
379        Key: null_mut(),
380    };
381    let mut iosb = IO_STATUS_BLOCK::default();
382    // SAFETY: caller guarantees contract.
383    unsafe {
384        chk_status(NtSetInformationFile(
385            handle,
386            &mut iosb,
387            std::ptr::from_mut::<FILE_COMPLETION_INFORMATION>(&mut info).cast(),
388            size_of_val(&info) as u32,
389            FileReplaceCompletionInformation,
390        ))?;
391    }
392    Ok(())
393}
394
395/// Wrapper around an NT IO completion packet, used to deliver wait results to
396/// IO completion ports.
397#[derive(Debug)]
398pub struct WaitPacket(OwnedHandle);
399
400impl WaitPacket {
401    /// Creates a new wait copmletion packet.
402    pub fn new() -> Result<Self> {
403        unsafe {
404            let mut handle = null_mut();
405            chk_status(NtCreateWaitCompletionPacket(&mut handle, 1, null_mut()))?;
406            Ok(Self(OwnedHandle::from_raw_handle(handle)))
407        }
408    }
409
410    /// Initiates a wait on `handle`. When `handle` becomes signaled, the packet
411    /// information will be delivered via `iocp`. Returns true if the handle was
412    /// already signaled (in which case the packet will still be delivered
413    /// through the IOCP).
414    ///
415    /// Panics if the wait could not be associated (e.g. invalid handle or wait
416    /// already in progress).
417    ///
418    /// # Safety
419    ///
420    /// The caller must ensure that `handle` is valid.
421    pub unsafe fn associate(
422        &self,
423        iocp: &IoCompletionPort,
424        handle: RawHandle,
425        key: usize,
426        apc: usize,
427        status: i32,
428        information: usize,
429    ) -> bool {
430        // SAFETY: API is being used as documented, and handle is valid
431        unsafe {
432            let mut already_signaled = 0;
433            chk_status(NtAssociateWaitCompletionPacket(
434                self.0.as_raw_handle(),
435                iocp.as_handle().as_raw_handle(),
436                handle,
437                key as *mut c_void,
438                apc as *mut c_void,
439                status,
440                information,
441                &mut already_signaled,
442            ))
443            .expect("failed to associate wait completion packet");
444            already_signaled != 0
445        }
446    }
447
448    /// Cancels a pending wait. Returns true if the wait was successfully
449    /// cancelled. If `remove_signaled_packet`, then the packet will be removed
450    /// from the IOCP (in which case it may have already consumed the signal
451    /// state of the object that was being waited upon).
452    pub fn cancel(&self, remove_signaled_packet: bool) -> bool {
453        match unsafe {
454            NtCancelWaitCompletionPacket(self.0.as_raw_handle(), remove_signaled_packet.into())
455        } {
456            ntstatus::STATUS_SUCCESS => true,
457            STATUS_PENDING => false,
458            ntstatus::STATUS_CANCELLED => false,
459            s => panic!(
460                "unexpected failure in NtCancelWaitCompletionPacket: {:?}",
461                chk_status(s).unwrap_err()
462            ),
463        }
464    }
465}
466
467impl AsHandle for WaitPacket {
468    fn as_handle(&self) -> BorrowedHandle<'_> {
469        self.0.as_handle()
470    }
471}
472
473// Represents a UNICODE_STRING that owns its buffer, where the buffer is
474// allocated on the Windows heap.
475#[repr(transparent)]
476pub struct UnicodeString(UNICODE_STRING);
477
478// SAFETY: UnicodeString owns its heap-allocated pointers, which can be safely
479//         aliased and sent between threads.
480unsafe impl Send for UnicodeString {}
481unsafe impl Sync for UnicodeString {}
482
483#[derive(Debug)]
484pub struct StringTooLong;
485
486impl UnicodeString {
487    pub fn new(s: &[u16]) -> std::result::Result<Self, StringTooLong> {
488        let byte_count: u16 = (s.len() * 2).try_into().map_err(|_| StringTooLong)?;
489        // FUTURE: use RtlProcessHeap instead of GetProcessHeap. This relies on
490        // unstable Rust features to get the PEB.
491        unsafe {
492            let buf = RtlAllocateHeap(GetProcessHeap(), 0, byte_count.into()).cast::<u16>();
493            assert!(!buf.is_null(), "out of memory");
494            std::ptr::copy(s.as_ptr(), buf, s.len());
495            Ok(Self(UNICODE_STRING {
496                Length: byte_count,
497                MaximumLength: byte_count,
498                Buffer: buf,
499            }))
500        }
501    }
502
503    pub fn empty() -> Self {
504        Self(unsafe { zeroed() })
505    }
506
507    pub fn is_empty(&self) -> bool {
508        self.0.Buffer.is_null()
509    }
510
511    pub fn as_ptr(&self) -> *const UNICODE_STRING {
512        &self.0
513    }
514
515    pub fn as_mut_ptr(&mut self) -> *mut UNICODE_STRING {
516        &mut self.0
517    }
518
519    pub fn into_raw(mut self) -> UNICODE_STRING {
520        let raw = self.0;
521        self.0.Length = 0;
522        self.0.MaximumLength = 0;
523        self.0.Buffer = null_mut();
524        raw
525    }
526
527    pub fn as_slice(&self) -> &[u16] {
528        let buffer = NonNull::new(self.0.Buffer).unwrap_or_else(NonNull::dangling);
529        unsafe { std::slice::from_raw_parts(buffer.as_ptr(), self.0.Length as usize / 2) }
530    }
531
532    pub fn as_mut_slice(&mut self) -> &mut [u16] {
533        let buffer = NonNull::new(self.0.Buffer).unwrap_or_else(NonNull::dangling);
534        unsafe { std::slice::from_raw_parts_mut(buffer.as_ptr(), self.0.Length as usize / 2) }
535    }
536}
537
538impl Drop for UnicodeString {
539    fn drop(&mut self) {
540        unsafe {
541            RtlFreeUnicodeString(&mut self.0);
542        }
543    }
544}
545
546impl<'a> TryFrom<&'a OsStr> for UnicodeString {
547    type Error = StringTooLong;
548    fn try_from(value: &'a OsStr) -> std::result::Result<Self, Self::Error> {
549        // FUTURE: figure out how to do this without a second allocation.
550        let value16: Vec<_> = value.encode_wide().collect();
551        Self::new(&value16)
552    }
553}
554
555impl<'a> TryFrom<&'a str> for UnicodeString {
556    type Error = StringTooLong;
557    fn try_from(value: &'a str) -> std::result::Result<Self, Self::Error> {
558        Self::try_from(OsStr::new(value))
559    }
560}
561
562impl TryFrom<String> for UnicodeString {
563    type Error = StringTooLong;
564    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
565        Self::try_from(OsStr::new(&value))
566    }
567}
568
569impl<'a> TryFrom<&'a Path> for UnicodeString {
570    type Error = StringTooLong;
571    fn try_from(value: &'a Path) -> std::result::Result<Self, Self::Error> {
572        Self::try_from(OsStr::new(value))
573    }
574}
575
576#[repr(transparent)]
577#[derive(Copy, Clone)]
578pub struct UnicodeStringRef<'a>(UNICODE_STRING, PhantomData<&'a [u16]>);
579
580impl<'a> UnicodeStringRef<'a> {
581    pub fn new(s: &'a [u16]) -> Option<Self> {
582        let len: u16 = (s.len() * 2).try_into().ok()?;
583        Some(Self(
584            UNICODE_STRING {
585                Length: len,
586                MaximumLength: len,
587                Buffer: s.as_ptr().cast_mut(),
588            },
589            PhantomData,
590        ))
591    }
592
593    pub fn empty() -> Self {
594        Self(unsafe { zeroed() }, PhantomData)
595    }
596
597    pub fn is_empty(&self) -> bool {
598        self.0.Buffer.is_null()
599    }
600
601    pub fn as_ptr(&self) -> *const UNICODE_STRING {
602        &self.0
603    }
604
605    pub fn as_mut_ptr(&mut self) -> *mut UNICODE_STRING {
606        &mut self.0
607    }
608
609    pub fn as_slice(&self) -> &[u16] {
610        let buffer = NonNull::new(self.0.Buffer).unwrap_or_else(NonNull::dangling);
611        unsafe { std::slice::from_raw_parts(buffer.as_ptr(), self.0.Length as usize / 2) }
612    }
613}
614
615pub trait AsUnicodeStringRef {
616    fn as_unicode_string_ref(&self) -> &UnicodeStringRef<'_>;
617}
618
619impl<T: AsUnicodeStringRef> AsUnicodeStringRef for &T {
620    fn as_unicode_string_ref(&self) -> &UnicodeStringRef<'_> {
621        (*self).as_unicode_string_ref()
622    }
623}
624
625impl AsUnicodeStringRef for UnicodeString {
626    fn as_unicode_string_ref(&self) -> &UnicodeStringRef<'_> {
627        // SAFETY: &UnicodeStringRef can be safely transmuted from
628        // &UNICODE_STRING as long as the lifetimes are correct, and they are
629        // here because the UnicodeStringRef will live no longer than self.
630        unsafe { std::mem::transmute(&self.0) }
631    }
632}
633
634impl AsUnicodeStringRef for UnicodeStringRef<'_> {
635    fn as_unicode_string_ref(&self) -> &UnicodeStringRef<'_> {
636        self
637    }
638}
639
640impl AsRef<windows::Win32::Foundation::UNICODE_STRING> for UnicodeStringRef<'_> {
641    fn as_ref(&self) -> &windows::Win32::Foundation::UNICODE_STRING {
642        // SAFETY: These are different definitions of the same type, so the memory layout is the
643        // same.
644        unsafe { std::mem::transmute(&self.0) }
645    }
646}
647
648impl<'a> TryFrom<&'a Utf16Str> for UnicodeStringRef<'a> {
649    type Error = StringTooLong;
650
651    fn try_from(value: &'a Utf16Str) -> std::result::Result<Self, Self::Error> {
652        UnicodeStringRef::new(value.as_slice()).ok_or(StringTooLong)
653    }
654}
655
656/// Associates an ANSI_STRING with the lifetime of the buffer.
657#[repr(transparent)]
658pub struct AnsiStringRef<'a>(ANSI_STRING, PhantomData<&'a [u8]>);
659
660impl<'a> AnsiStringRef<'a> {
661    /// Creates a new `AnsiStringRef` using the specified buffer.
662    ///
663    /// Returns `None` if the buffer is too big for an ANSI_STRING's maximum length.
664    pub fn new(s: &'a [u8]) -> Option<Self> {
665        let len: u16 = s.len().try_into().ok()?;
666        Some(Self(
667            ANSI_STRING {
668                Length: len,
669                MaximumLength: len,
670                Buffer: s.as_ptr() as *mut i8,
671            },
672            PhantomData,
673        ))
674    }
675
676    /// Creates an empty `AnsiStringRef` with no buffer.
677    pub fn empty() -> Self {
678        Self(unsafe { zeroed() }, PhantomData)
679    }
680
681    /// Gets a value which indicates whether this instance does not contain a buffer.
682    pub fn is_empty(&self) -> bool {
683        self.0.Buffer.is_null()
684    }
685
686    /// Returns a pointer to the contained `ANSI_STRING`
687    pub fn as_ptr(&self) -> *const ANSI_STRING {
688        &self.0
689    }
690
691    /// Returns a mutable pointer to the contained `ANSI_STRING`
692    pub fn as_mut_ptr(&mut self) -> *mut ANSI_STRING {
693        &mut self.0
694    }
695
696    /// Returns the valid part of an ANSI_STRING's buffer as a slice.
697    pub fn as_slice(&self) -> &[u8] {
698        let buffer = NonNull::new(self.0.Buffer.cast::<u8>()).unwrap_or_else(NonNull::dangling);
699        unsafe { std::slice::from_raw_parts(buffer.as_ptr(), self.0.Length as usize) }
700    }
701}
702
703impl AsRef<ANSI_STRING> for AnsiStringRef<'_> {
704    fn as_ref(&self) -> &ANSI_STRING {
705        &self.0
706    }
707}
708
709pub fn status_to_error(status: i32) -> Error {
710    Error::from_raw_os_error(unsafe { RtlNtStatusToDosErrorNoTeb(status) } as i32)
711}
712
713pub fn chk_status(status: i32) -> Result<i32> {
714    if status >= 0 {
715        Ok(status)
716    } else {
717        Err(status_to_error(status))
718    }
719}
720
721pub fn dos_to_nt_path<P: AsRef<Path>>(path: P) -> Result<UnicodeString> {
722    let path16 = U16CString::from_os_str(path.as_ref().as_os_str())
723        .map_err(|_| Error::from_raw_os_error(ERROR_BAD_PATHNAME as i32))?;
724    let mut pathu = UnicodeString::empty();
725    unsafe {
726        chk_status(RtlDosPathNameToNtPathName_U_WithStatus(
727            path16.as_ptr().cast_mut(),
728            pathu.as_mut_ptr(),
729            null_mut(),
730            null_mut(),
731        ))?;
732    }
733    Ok(pathu)
734}
735
736/// A wrapper around OBJECT_ATTRIBUTES.
737#[repr(transparent)]
738pub struct ObjectAttributes<'a> {
739    attributes: ntdef::OBJECT_ATTRIBUTES,
740    phantom: PhantomData<&'a ()>,
741}
742
743impl Default for ObjectAttributes<'_> {
744    fn default() -> Self {
745        Self::new()
746    }
747}
748
749impl<'a> ObjectAttributes<'a> {
750    /// Constructs the default object attributes, with no name, root directory,
751    /// attributes, or security information.
752    pub fn new() -> Self {
753        Self {
754            attributes: ntdef::OBJECT_ATTRIBUTES {
755                Length: size_of::<ntdef::OBJECT_ATTRIBUTES>() as u32,
756                RootDirectory: null_mut(),
757                ObjectName: null_mut(),
758                Attributes: 0,
759                SecurityDescriptor: null_mut(),
760                SecurityQualityOfService: null_mut(),
761            },
762            phantom: PhantomData,
763        }
764    }
765
766    /// Sets the object name to `name`.
767    pub fn name<P>(&mut self, name: &'a P) -> &mut Self
768    where
769        P: AsUnicodeStringRef,
770    {
771        self.attributes.ObjectName = name.as_unicode_string_ref().as_ptr().cast_mut();
772        self
773    }
774
775    /// Sets the root directory to `root`.
776    pub fn root(&mut self, root: BorrowedHandle<'a>) -> &mut Self {
777        self.attributes.RootDirectory = root.as_raw_handle();
778        self
779    }
780
781    /// Sets the attributes to `attributes`.
782    pub fn attributes(&mut self, attributes: u32) -> &mut Self {
783        self.attributes.Attributes = attributes;
784        self
785    }
786
787    /// Sets the security descriptor to `sd`.
788    pub fn security_descriptor(&mut self, sd: &'a SecurityDescriptor) -> &mut Self {
789        self.attributes.SecurityDescriptor = sd.as_ptr();
790        self
791    }
792
793    /// Returns the OBJECT_ATTRIBUTES pointer for passing to an NT syscall.
794    pub fn as_ptr(&self) -> *mut ntdef::OBJECT_ATTRIBUTES {
795        std::ptr::from_ref(&self.attributes).cast_mut()
796    }
797}
798
799impl AsRef<windows::Wdk::Foundation::OBJECT_ATTRIBUTES> for ObjectAttributes<'_> {
800    fn as_ref(&self) -> &windows::Wdk::Foundation::OBJECT_ATTRIBUTES {
801        // SAFETY: These are different definitions of the same type, so the memory layout is the
802        // same.
803        unsafe { std::mem::transmute(&self.attributes) }
804    }
805}
806
807pub fn open_object_directory(obj_attr: &ObjectAttributes<'_>, access: u32) -> Result<OwnedHandle> {
808    // SAFETY: calling the API according to the NT API
809    unsafe {
810        let mut handle = null_mut();
811        chk_status(NtOpenDirectoryObject(
812            &mut handle,
813            access,
814            obj_attr.as_ptr(),
815        ))?;
816        Ok(OwnedHandle::from_raw_handle(handle))
817    }
818}
819
820pub fn create_object_directory(
821    obj_attr: &ObjectAttributes<'_>,
822    access: u32,
823) -> Result<OwnedHandle> {
824    // SAFETY: calling the API according to the NT API
825    unsafe {
826        let mut handle = null_mut();
827        chk_status(NtCreateDirectoryObject(
828            &mut handle,
829            access,
830            obj_attr.as_ptr(),
831        ))?;
832        Ok(OwnedHandle::from_raw_handle(handle))
833    }
834}
835
836/// A wrapper around memory that was allocated with `RtlAllocateHeap` and will be freed on drop with `RtlFreeHeap`,
837/// like [`std::boxed::Box`].
838pub struct RtlHeapBox<T: ?Sized> {
839    value: NonNull<T>,
840}
841
842impl<T> RtlHeapBox<T> {
843    /// Creates a new `RtlHeapBox` from a raw pointer.
844    ///
845    /// # Safety
846    ///
847    /// The caller must guarantee that the pointer was allocated with `RtlAllocateHeap` with the default heap of the current
848    /// process as the heap handle, returned by `GetProcessHeap`.
849    ///
850    /// The caller must not allow this pointer to be aliased anywhere else. Conceptually, by calling `from_raw`, the caller
851    /// must guarantee that ownership of the pointer `value` is transferred to this `RtlHeapBox`. This is to uphold the aliasing
852    /// requirements used by `RtlHeapBox` to implement various Deref and AsRef traits.
853    ///
854    /// On drop, this memory will be freed with `RtlFreeHeap`. The caller must not manually free this pointer.
855    pub unsafe fn from_raw(value: *mut T) -> Self {
856        Self {
857            value: NonNull::new(value).unwrap(),
858        }
859    }
860
861    /// Gets the contained pointer.
862    pub fn as_ptr(&self) -> *const T {
863        self.value.as_ptr()
864    }
865}
866
867impl<T> std::ops::Deref for RtlHeapBox<T> {
868    type Target = T;
869    fn deref(&self) -> &Self::Target {
870        // SAFETY: The pointer held by the RtlHeapBox is guaranteed to be valid and conform to the rules required by NonNull::as_ref.
871        unsafe { self.value.as_ref() }
872    }
873}
874
875impl<T> std::ops::DerefMut for RtlHeapBox<T> {
876    fn deref_mut(&mut self) -> &mut T {
877        // SAFETY: The pointer held by the RtlHeapBox is guaranteed to be valid and conform to the rules required by NonNull::as_mut.
878        unsafe { self.value.as_mut() }
879    }
880}
881
882impl<T> AsRef<T> for RtlHeapBox<T> {
883    fn as_ref(&self) -> &T {
884        // SAFETY: The pointer held by the RtlHeapBox is guaranteed to be valid and conform to the rules required by NonNull::as_ref.
885        unsafe { self.value.as_ref() }
886    }
887}
888
889impl<T> AsMut<T> for RtlHeapBox<T> {
890    fn as_mut(&mut self) -> &mut T {
891        // SAFETY: The pointer held by the RtlHeapBox is guaranteed to be valid and conform to the rules required by NonNull::as_mut.
892        unsafe { self.value.as_mut() }
893    }
894}
895
896impl<T: ?Sized> Drop for RtlHeapBox<T> {
897    fn drop(&mut self) {
898        // SAFETY: The pointer held by the RtlHeapBox must be allocated via RtlAllocateHeap from the constraints in
899        //         RtlHeapBox::from_raw.
900        unsafe {
901            ntrtl::RtlFreeHeap(GetProcessHeap(), 0, self.value.as_ptr().cast::<c_void>());
902        }
903    }
904}
905
906/// A wrapper around a sized buffer that was allocated with RtlAllocateHeap. This allows extracting a slice via helper methods
907/// instead of using [`RtlHeapBox`] directly.
908pub struct RtlHeapBuffer {
909    buffer: RtlHeapBox<u8>,
910    size: usize,
911}
912
913impl RtlHeapBuffer {
914    /// Creates a new `HeapBuffer` from a raw pointer and size.
915    ///
916    /// # Safety
917    ///
918    /// The caller must guarantee that the pointer `buffer` conforms to the safety requirements imposed by [`RtlHeapBox::from_raw`].
919    ///
920    /// Additionally, the pointer described by `buffer` must describe a [`u8`] array of count `size`.
921    pub unsafe fn from_raw(buffer: *mut u8, size: usize) -> RtlHeapBuffer {
922        Self {
923            // SAFETY: The caller has guaranteed that this pointer is an RtlAllocateHeap pointer and should be managed
924            //         via a RtlHeapBox.
925            buffer: unsafe { RtlHeapBox::from_raw(buffer) },
926            size,
927        }
928    }
929}
930
931impl std::ops::Deref for RtlHeapBuffer {
932    type Target = [u8];
933    fn deref(&self) -> &Self::Target {
934        // SAFETY: The pointer described by buffer is a u8 array of self.size, as required in RtlHeapBuffer::from_raw.
935        unsafe { std::slice::from_raw_parts(self.buffer.as_ptr(), self.size) }
936    }
937}
938
939/// `Send`+`Sync` wrapper around `OVERLAPPED`.
940///
941/// Internally uses an UnsafeCell since this may be concurrently updated by the
942/// kernel.
943#[repr(transparent)]
944#[derive(Default, Debug)]
945pub struct Overlapped(UnsafeCell<OVERLAPPED>);
946
947impl Overlapped {
948    pub fn new() -> Self {
949        Default::default()
950    }
951
952    /// Sets the offset for the IO request.
953    pub fn set_offset(&mut self, offset: i64) {
954        let overlapped = self.0.get_mut();
955        // SAFETY: Writing to union field.
956        unsafe {
957            overlapped.u.s_mut().Offset = offset as u32;
958            overlapped.u.s_mut().OffsetHigh = (offset >> 32) as u32;
959        }
960    }
961
962    pub fn set_event(&mut self, event: RawHandle) {
963        self.0.get_mut().hEvent = event;
964    }
965
966    pub fn as_ptr(&self) -> *mut OVERLAPPED {
967        self.0.get()
968    }
969
970    /// Polls the current operation status.
971    pub fn io_status(&self) -> Option<(NTSTATUS, usize)> {
972        let overlapped = self.0.get();
973        // SAFETY: The kernel might be mutating the overlapped structure right
974        // now, so this gets a &AtomicUsize just to the Internal field that
975        // contains the completion status.
976        let internal = unsafe { &*addr_of!((*overlapped).Internal).cast::<AtomicUsize>() };
977        let status = internal.load(Ordering::Acquire) as NTSTATUS;
978        if status != STATUS_PENDING {
979            // SAFETY: the IO is complete so it's safe to read this value directly.
980            let information = unsafe { (*self.0.get()).InternalHigh };
981            Some((status, information))
982        } else {
983            None
984        }
985    }
986}
987
988// SAFETY: By itself, an overlapped structure can be safely sent or shared
989// across multiple threads. Of course, while it is owned by the kernel is cannot
990// be concurrently accessed, but this has no bearing on its Send/Sync-ness.
991unsafe impl Send for Overlapped {}
992// SAFETY: See above comment.
993unsafe impl Sync for Overlapped {}
994
995#[macro_export]
996macro_rules! delayload {
997    {$dll:literal {$($($idents:ident)+ ($($params:ident : $types:ty),* $(,)?) -> $result:ty;)*}} => {
998        fn get_module() -> Result<::winapi::shared::minwindef::HINSTANCE, u32> {
999            use ::std::ptr::null_mut;
1000            use ::std::sync::atomic::{AtomicPtr, Ordering};
1001            use ::winapi::{
1002                um::{
1003                    errhandlingapi::GetLastError,
1004                    libloaderapi::{FreeLibrary, LoadLibraryA},
1005                },
1006            };
1007
1008            static MODULE: AtomicPtr<::winapi::shared::minwindef::HINSTANCE__> = AtomicPtr::new(null_mut());
1009            let mut module = MODULE.load(Ordering::Relaxed);
1010            if module.is_null() {
1011                module = unsafe { LoadLibraryA(concat!($dll, "\0").as_ptr() as *const i8) };
1012                if module.is_null() {
1013                    return Err(unsafe { GetLastError() });
1014                }
1015                let old_module = MODULE.swap(module, Ordering::Relaxed);
1016                if !old_module.is_null() {
1017                    unsafe { FreeLibrary(old_module) };
1018                }
1019            }
1020            Ok(module)
1021        }
1022
1023        $(
1024            $crate::delayload! { @func $($idents)* ($($params:$types),*) -> $result }
1025        )*
1026    };
1027
1028    (@func pub fn $name:ident($($params:ident : $types:ty),* $(,)?) -> $result:ty) => {
1029        #[expect(non_snake_case, clippy::too_many_arguments, clippy::diverging_sub_expression)]
1030        pub unsafe fn $name($($params: $types,)*) -> $result {
1031            $crate::delayload!(@body $name($($params : $types),*) -> $result)
1032        }
1033    };
1034
1035    (@func fn $name:ident($($params:ident : $types:ty),* $(,)?) -> $result:ty) => {
1036        #[expect(non_snake_case, clippy::diverging_sub_expression)]
1037        unsafe fn $name($($params: $types,)*) -> $result {
1038            $crate::delayload!(@body $name($($params : $types),*) -> $result)
1039        }
1040    };
1041
1042    (@body $name:ident($($params:ident : $types:ty),* $(,)?) -> $result:ty) => {
1043        {
1044            use ::winapi::{
1045                shared::winerror::ERROR_PROC_NOT_FOUND,
1046                um::libloaderapi::GetProcAddress,
1047            };
1048            use ::std::concat;
1049            use ::std::sync::atomic::{AtomicUsize, Ordering};
1050
1051            static FNCELL: AtomicUsize = AtomicUsize::new(0);
1052            let mut fnval = FNCELL.load(Ordering::Relaxed);
1053            if fnval == 0 {
1054                #[allow(unreachable_code)]
1055                match get_module() {
1056                    Ok(module) => {
1057                        fnval = GetProcAddress(
1058                            module,
1059                            concat!(stringify!($name), "\0").as_ptr() as *const i8)
1060                        as usize;
1061                    }
1062                    Err(e) => return $crate::delayload!(@result_from_win32(($result), e)),
1063                }
1064                if fnval == 0 {
1065                    fnval = 1;
1066                }
1067                FNCELL.store(fnval, Ordering::Relaxed);
1068            }
1069            if fnval == 1 {
1070                #[allow(unreachable_code)]
1071                return $crate::delayload!(@result_from_win32(($result), ERROR_PROC_NOT_FOUND));
1072            }
1073            type FnType = unsafe extern "stdcall" fn($($params: $types,)*) -> $result;
1074            let fnptr: FnType = ::std::mem::transmute(fnval);
1075            fnptr($($params,)*)
1076        }
1077    };
1078
1079    (@result_from_win32((i32), $val:expr)) => { ::winapi::shared::winerror::HRESULT_FROM_WIN32($val) };
1080    (@result_from_win32((u32), $val:expr)) => { $val };
1081    (@result_from_win32((DWORD), $val:expr)) => { $val };
1082    (@result_from_win32((HRESULT), $val:expr)) => { ::winapi::shared::winerror::HRESULT_FROM_WIN32($val) };
1083    (@result_from_win32(($t:tt), $val:expr)) => { panic!("could not load: {}", $val) };
1084}
1085
1086/// Closes stdout, replacing it with the null device.
1087pub fn close_stdout() -> Result<()> {
1088    let new_stdout = File::open("nul")?;
1089    let stdout = io::stdout();
1090    // Prevent concurrent accesses to stdout.
1091    let _locked = stdout.lock();
1092    let old_handle = stdout.as_raw_handle();
1093    // SAFETY: transferring ownership of the new handle.
1094    unsafe {
1095        if SetStdHandle(STD_OUTPUT_HANDLE, new_stdout.into_raw_handle()) == 0 {
1096            panic!("failed to set handle");
1097        }
1098    }
1099    drop(_locked);
1100    unsafe {
1101        // SAFETY: the old handle is no longer referenced anywhere.
1102        CloseHandle(old_handle);
1103    }
1104
1105    Ok(())
1106}
1107
1108/// Disables the hard error dialog on "critical errors".
1109pub fn disable_hard_error_dialog() {
1110    // SAFETY: This Win32 API has no safety requirements.
1111    unsafe {
1112        SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS);
1113    }
1114}
1115
1116#[cfg(test)]
1117mod tests {
1118    use super::*;
1119
1120    #[test]
1121    fn test_dos_to_nt_path() {
1122        let pathu = dos_to_nt_path("c:\\foo").unwrap();
1123        assert!(
1124            pathu
1125                .as_slice()
1126                .iter()
1127                .copied()
1128                .eq("\\??\\c:\\foo".encode_utf16())
1129        );
1130    }
1131
1132    #[test]
1133    fn test_alloc_unicode_string() {
1134        let s: UnicodeString = "abc".try_into().unwrap();
1135        assert!(s.as_slice().iter().copied().eq("abc".encode_utf16()));
1136    }
1137}