|
1 | 1 | use crate::driver::{Entry, Poller}; |
2 | 2 | use crossbeam_queue::SegQueue; |
3 | 3 | use std::{ |
| 4 | + ffi::c_void, |
4 | 5 | io, |
5 | 6 | os::windows::{ |
6 | 7 | io::HandleOrNull, |
7 | 8 | prelude::{AsRawHandle, OwnedHandle, RawHandle}, |
8 | 9 | }, |
9 | | - ptr::null_mut, |
| 10 | + ptr::{null, null_mut}, |
10 | 11 | task::Poll, |
11 | 12 | time::Duration, |
12 | 13 | }; |
13 | 14 | use windows_sys::Win32::{ |
14 | | - Foundation::{GetLastError, ERROR_HANDLE_EOF, INVALID_HANDLE_VALUE, WAIT_TIMEOUT}, |
| 15 | + Foundation::{ |
| 16 | + GetLastError, RtlNtStatusToDosError, ERROR_HANDLE_EOF, INVALID_HANDLE_VALUE, NTSTATUS, |
| 17 | + STATUS_SUCCESS, WAIT_TIMEOUT, |
| 18 | + }, |
15 | 19 | System::{ |
16 | 20 | Threading::INFINITE, |
| 21 | + WindowsProgramming::{FILE_INFORMATION_CLASS, IO_STATUS_BLOCK}, |
17 | 22 | IO::{ |
18 | 23 | CreateIoCompletionPort, GetQueuedCompletionStatus, PostQueuedCompletionStatus, |
19 | 24 | OVERLAPPED, |
@@ -91,8 +96,54 @@ impl Driver { |
91 | 96 | } |
92 | 97 | } |
93 | 98 |
|
| 99 | +fn deattach_iocp(fd: RawFd) -> io::Result<()> { |
| 100 | + #[link(name = "ntdll")] |
| 101 | + extern "system" { |
| 102 | + fn NtSetInformationFile( |
| 103 | + FileHandle: usize, |
| 104 | + IoStatusBlock: *mut IO_STATUS_BLOCK, |
| 105 | + FileInformation: *const c_void, |
| 106 | + Length: u32, |
| 107 | + FileInformationClass: FILE_INFORMATION_CLASS, |
| 108 | + ) -> NTSTATUS; |
| 109 | + } |
| 110 | + #[allow(non_upper_case_globals)] |
| 111 | + const FileReplaceCompletionInformation: FILE_INFORMATION_CLASS = 61; |
| 112 | + #[repr(C)] |
| 113 | + #[allow(non_camel_case_types)] |
| 114 | + #[allow(non_snake_case)] |
| 115 | + struct FILE_COMPLETION_INFORMATION { |
| 116 | + Port: usize, |
| 117 | + Key: *const c_void, |
| 118 | + } |
| 119 | + |
| 120 | + let mut block = unsafe { std::mem::zeroed() }; |
| 121 | + let info = FILE_COMPLETION_INFORMATION { |
| 122 | + Port: 0, |
| 123 | + Key: null(), |
| 124 | + }; |
| 125 | + unsafe { |
| 126 | + NtSetInformationFile( |
| 127 | + fd as _, |
| 128 | + &mut block, |
| 129 | + &info as *const _ as _, |
| 130 | + std::mem::size_of_val(&info) as _, |
| 131 | + FileReplaceCompletionInformation, |
| 132 | + ) |
| 133 | + }; |
| 134 | + let res = unsafe { block.Anonymous.Status }; |
| 135 | + if res != STATUS_SUCCESS { |
| 136 | + Err(io::Error::from_raw_os_error(unsafe { |
| 137 | + RtlNtStatusToDosError(res) as _ |
| 138 | + })) |
| 139 | + } else { |
| 140 | + Ok(()) |
| 141 | + } |
| 142 | +} |
| 143 | + |
94 | 144 | impl Poller for Driver { |
95 | 145 | fn attach(&self, fd: RawFd) -> io::Result<()> { |
| 146 | + deattach_iocp(fd)?; |
96 | 147 | let port = unsafe { CreateIoCompletionPort(fd as _, self.port.as_raw_handle() as _, 0, 0) }; |
97 | 148 | if port == 0 { |
98 | 149 | Err(io::Error::last_os_error()) |
|
0 commit comments