1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
//! I/O request packets (IRP).
use ::NTSTATUS;
use ::basedef::*;
use ::event::PKEVENT;
use ::device_object::*;
use ::file_object::*;
use ::basedef::IO_PRIORITY::*;
use ::KIRQL;
pub type PIRP = *mut IRP;
pub type PIO_STACK_LOCATION = *mut IO_STACK_LOCATION;
// NOTE: fastcall is broken: https://github.com/rust-lang/rust/issues/18086
//extern "fastcall" { fn IofCompleteRequest(Irp: PIRP, PriorityBoost: KPRIORITY_BOOST); }
extern "system"
{
fn IoCompleteRequest(Irp: PIRP, PriorityBoost: KPRIORITY_BOOST);
pub fn IoAllocateIrp(StackSize: CCHAR, ChargeQuota: bool) -> PIRP;
pub fn IoFreeIrp(Irp: PIRP);
pub fn IoReuseIrp(Irp: PIRP, Status: NTSTATUS);
pub fn IoInitializeIrp(Irp: PIRP, PacketSize: USHORT, StackSize: CCHAR);
pub fn IoMakeAssociatedIrp(Irp: PIRP, StackSize: CCHAR) -> PIRP;
// unfortunately following are macro
// fn IoGetCurrentIrpStackLocation(Irp: PIRP) -> PIO_STACK_LOCATION;
// fn IoGetNextIrpStackLocation(Irp: PIRP) -> PIO_STACK_LOCATION;
// fn IoSetNextIrpStackLocation(Irp: PIRP);
// fn IoSkipCurrentIrpStackLocation(Irp: PIRP);
}
/// `IRP` Major Function Codes.
///
/// For information about these requests, see
/// [IRP Major Function Codes](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548603%28v=vs.85%29.aspx).
#[repr(u8)]
pub enum IRP_MJ
{
/// The operating system sends this request to open a handle to a file object or device object.
CREATE,
CREATE_NAMED_PIPE,
/// Indicates that the last handle of the file object that is associated with the target device object
/// has been closed and released. All outstanding I/O requests have been completed or canceled.
/// See also `CLEANUP`.
CLOSE,
/// A user-mode application or Win32 component has requested a data transfer from the device.
/// Or a higher-level driver has created and set up the read IRP.
READ,
/// A user-mode application or Win32 component has requested a data transfer to the device.
/// Or a higher-level driver has created and set up the write IRP.
WRITE,
QUERY_INFORMATION,
SET_INFORMATION,
QUERY_EA,
SET_EA,
/// Indicates that the driver should flush the device's cache or its internal buffer,
/// or, possibly, should discard the data in its internal buffer.
FLUSH_BUFFERS,
QUERY_VOLUME_INFORMATION,
SET_VOLUME_INFORMATION,
DIRECTORY_CONTROL,
FILE_SYSTEM_CONTROL,
/// An user-mode thread has called the Microsoft Win32 `DeviceIoControl` function, or a higher-level kernel-mode driver has set up the request.
DEVICE_CONTROL,
/// Some driver calls either `IoBuildDeviceIoControlRequest` or `IoAllocateIrp` to create a request.
INTERNAL_DEVICE_CONTROL,
/// Indicates that a file system driver is sending notice that the system is being shut down.
SHUTDOWN,
LOCK_CONTROL,
/// Indicates that the last handle for a file object that is associated with the target device object has been closed
/// (but, due to outstanding I/O requests, might not have been released).
/// See also `CLOSE`.
CLEANUP,
CREATE_MAILSLOT,
QUERY_SECURITY,
SET_SECURITY,
POWER,
SYSTEM_CONTROL,
DEVICE_CHANGE,
QUERY_QUOTA,
SET_QUOTA,
PNP,
MAXIMUM_FUNCTION,
}
/// The `IRP` structure is a partial opaque structure that represents an I/O request packet.
#[repr(C)]
pub struct IRP
{
pub Type: u16,
pub Size: u16,
/// Pointer to an `MDL` describing a user buffer, if the driver is using direct I/O.
pub MdlAddress: PVOID,
/// Flags word - used to remember various flags.
pub Flags: u32,
/// Pointer to a system-space buffer if the driver is using buffered I/O.
pub SystemBuffer: PVOID,
pub ThreadListEntry: LIST_ENTRY,
/// I/O status - final status of operation.
pub IoStatus: IO_STATUS_BLOCK,
/// Indicates the execution mode of the original requester of the operation.
pub RequestorMode: KPROCESSOR_MODE,
/// If set to `TRUE`, a driver has marked the IRP pending.
pub PendingReturned: bool,
/// Stack state information.
pub StackCount: i8,
/// Stack state information.
pub CurrentLocation: i8,
/// If set to `TRUE`, the IRP either is or should be canceled.
pub Cancel: bool,
/// Irql at which the cancel spinlock was acquired.
pub CancelIrql: KIRQL,
pub ApcEnvironment: u8,
/// Allocation control flags.
pub AllocationFlags: u8,
/// User parameters.
pub UserIosb: PIO_STATUS_BLOCK,
pub UserEvent: PKEVENT,
// union {
pub UserApcRoutine: PIO_APC_ROUTINE,
pub UserApcContext: PVOID,
// } Overlay
/// Contains the entry point for a driver-supplied `Cancel` routine to be called if the IRP is canceled.
pub CancelRoutine: PDRIVER_CANCEL,
/// Contains the address of an output buffer for `IRP_MJ_DEVICE_CONTROL`.
pub UserBuffer: PVOID,
/// Kernel structures.
// union {
pub Overlay: _IRP_OVERLAY,
// } Tail
}
/// Kernel structures for IRP.
#[repr(C)]
pub struct _IRP_OVERLAY
{
pub DriverContext: [PVOID; 4],
pub Thread: PETHREAD,
pub AuxiliaryBuffer: PVOID,
pub ListEntry: LIST_ENTRY,
/// Current stack location.
pub CurrentStackLocation: PIO_STACK_LOCATION,
pub OriginalFileObject: PFILE_OBJECT,
}
pub const SL_PENDING_RETURNED: u8 = 0x01;
pub const SL_INVOKE_ON_CANCEL: u8 = 0x20;
pub const SL_INVOKE_ON_SUCCESS: u8 = 0x40;
pub const SL_INVOKE_ON_ERROR: u8 = 0x80;
/// I/O Stack Locations.
#[repr(C)]
pub struct IO_STACK_LOCATION
{
/// The IRP major function code indicating the type of I/O operation to be performed.
pub MajorFunction: u8,
/// A subfunction code for `MajorFunction`.
pub MinorFunction: u8,
/// Request-type-specific values (see [DEVICE_FLAGS](../device_object/enum.DEVICE_FLAGS.html)).
pub Flags: u8,
/// Stack location control flags.
pub Control: u8,
/// A union that depends on the major and minor IRP function code values
/// contained in `MajorFunction` and `MinorFunction`.
// union Parameters
pub Parameters: [PVOID; 4],
/// A pointer to the driver-created `DEVICE_OBJECT` structure
/// representing the target physical, logical, or virtual device for which this driver is to handle the IRP.
pub DeviceObject: PDEVICE_OBJECT,
/// A pointer to a `FILE_OBJECT` structure that represents the file object, if any, that is associated with `DeviceObject` pointer.
pub FileObject: PFILE_OBJECT,
/// The following routine is invoked depending on the flags in the above `Flags` field.
pub CompletionRoutine: PIO_COMPLETION_ROUTINE,
/// The following is used to store the address of the context parameter that should be passed to the `CompletionRoutine`.
pub Context: PVOID,
}
/// Parameters for `IRP_MJ_READ`.
#[repr(C)]
pub struct _IO_STACK_LOCATION_READ
{
pub Length: u32,
pub Key: u32,
pub ByteOffset: i64,
}
impl IRP {
pub fn new(StackSize: i8) -> PIRP {
unsafe { IoAllocateIrp(StackSize, false) }
}
pub fn with_quota(StackSize: i8) -> PIRP {
unsafe { IoAllocateIrp(StackSize, true) }
}
pub fn free(&mut self) {
unsafe { IoFreeIrp(self) };
}
/// Returns a pointer to the caller's stack location in the given `IRP`.
pub fn get_current_stack_location(&mut self) -> &mut IO_STACK_LOCATION {
unsafe { &mut *self.Overlay.CurrentStackLocation }
}
/// Returns a pointer to the next-lower-level driver's I/O stack location.
pub fn get_next_stack_location(&mut self) -> &mut IO_STACK_LOCATION {
unsafe { &mut *self.Overlay.CurrentStackLocation.offset(-1) }
}
/// Indicates that the caller has completed all processing for a given I/O request
/// and is returning the given IRP to the I/O manager.
pub fn complete_request(&mut self, Status: NTSTATUS) -> NTSTATUS {
self.IoStatus.Status = Status;
unsafe { IoCompleteRequest(self, IO_NO_INCREMENT) };
return Status;
}
/// Registers an `IoCompletion` routine, which will be called when the next-lower-level driver
/// has completed the requested operation for the given IRP.
pub fn set_completion(&mut self, CompletionRoutine: PIO_COMPLETION_ROUTINE, Context: PVOID,
InvokeOnSuccess: bool, InvokeOnError: bool, InvokeOnCancel: bool)
{
let mut lower = self.get_next_stack_location();
lower.CompletionRoutine = CompletionRoutine;
lower.Context = Context;
lower.Control = 0;
if InvokeOnSuccess {
lower.Control |= SL_INVOKE_ON_SUCCESS;
}
if InvokeOnError {
lower.Control |= SL_INVOKE_ON_ERROR;
}
if InvokeOnCancel {
lower.Control |= SL_INVOKE_ON_CANCEL;
}
}
pub fn set_unconditional_completion(&mut self, CompletionRoutine: PIO_COMPLETION_ROUTINE, Context: PVOID) {
self.set_completion(CompletionRoutine, Context, true, true, true)
}
}
impl IO_STACK_LOCATION {
/// Access parameters for `IRP_MJ_READ`.
pub fn ParametersRead(&mut self) -> &mut _IO_STACK_LOCATION_READ {
unsafe { ::core::mem::transmute(&mut self.Parameters) }
}
}
|