Branch setupapi (again)
[reactos.git] / reactos / ntoskrnl / io / iocomp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/iocomp.c
5 * PURPOSE:
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 Changed NtQueryIoCompletion
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 #define IOC_TAG TAG('I', 'O', 'C', 'T')
19
20 POBJECT_TYPE ExIoCompletionType;
21
22 NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
23
24 static GENERIC_MAPPING ExIoCompletionMapping =
25 {
26 STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE,
27 STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE,
28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
29 IO_COMPLETION_ALL_ACCESS
30 };
31
32 /* FUNCTIONS *****************************************************************/
33
34 NTSTATUS
35 STDCALL
36 NtpCreateIoCompletion(
37 PVOID ObjectBody,
38 PVOID Parent,
39 PWSTR RemainingPath,
40 POBJECT_ATTRIBUTES ObjectAttributes
41 )
42 {
43 DPRINT("NtpCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n",
44 ObjectBody, Parent, RemainingPath);
45
46 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
47 {
48 return STATUS_UNSUCCESSFUL;
49 }
50
51 return STATUS_SUCCESS;
52 }
53
54 VOID STDCALL
55 NtpDeleteIoCompletion(PVOID ObjectBody)
56 {
57 PKQUEUE Queue = ObjectBody;
58
59 DPRINT("NtpDeleteIoCompletion()\n");
60
61 KeRundownQueue(Queue);
62 }
63
64
65 /*
66 * @unimplemented
67 */
68 NTSTATUS
69 STDCALL
70 IoSetCompletionRoutineEx(
71 IN PDEVICE_OBJECT DeviceObject,
72 IN PIRP Irp,
73 IN PIO_COMPLETION_ROUTINE CompletionRoutine,
74 IN PVOID Context,
75 IN BOOLEAN InvokeOnSuccess,
76 IN BOOLEAN InvokeOnError,
77 IN BOOLEAN InvokeOnCancel
78 )
79 {
80 UNIMPLEMENTED;
81 return STATUS_NOT_IMPLEMENTED;
82 }
83
84 /*
85 * @implemented
86 */
87 NTSTATUS
88 STDCALL
89 IoSetIoCompletion (
90 IN PVOID IoCompletion,
91 IN PVOID KeyContext,
92 IN PVOID ApcContext,
93 IN NTSTATUS IoStatus,
94 IN ULONG_PTR IoStatusInformation,
95 IN BOOLEAN Quota
96 )
97 {
98 PKQUEUE Queue = (PKQUEUE) IoCompletion;
99 PIO_COMPLETION_PACKET Packet;
100
101 Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
102 if (NULL == Packet)
103 {
104 return STATUS_NO_MEMORY;
105 }
106
107 Packet->Key = KeyContext;
108 Packet->Context = ApcContext;
109 Packet->IoStatus.Status = IoStatus;
110 Packet->IoStatus.Information = IoStatusInformation;
111
112 KeInsertQueue(Queue, &Packet->ListEntry);
113
114 return STATUS_SUCCESS;
115 }
116
117 VOID
118 FASTCALL
119 IopInitIoCompletionImplementation(VOID)
120 {
121 ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
122
123 RtlCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion");
124
125 ExIoCompletionType->Tag = IOC_TAG;
126 ExIoCompletionType->MaxObjects = ULONG_MAX;
127 ExIoCompletionType->MaxHandles = ULONG_MAX;
128 ExIoCompletionType->TotalObjects = 0;
129 ExIoCompletionType->TotalHandles = 0;
130 ExIoCompletionType->PagedPoolCharge = 0;
131 ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE);
132 ExIoCompletionType->Mapping = &ExIoCompletionMapping;
133 ExIoCompletionType->Dump = NULL;
134 ExIoCompletionType->Open = NULL;
135 ExIoCompletionType->Close = NULL;
136 ExIoCompletionType->Delete = NtpDeleteIoCompletion;
137 ExIoCompletionType->Parse = NULL;
138 ExIoCompletionType->Security = NULL;
139 ExIoCompletionType->QueryName = NULL;
140 ExIoCompletionType->OkayToClose = NULL;
141 ExIoCompletionType->Create = NtpCreateIoCompletion;
142 ExIoCompletionType->DuplicationNotify = NULL;
143
144 ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
145 NULL,
146 NULL,
147 0,
148 sizeof(IO_COMPLETION_PACKET),
149 IOC_TAG,
150 0);
151 }
152
153
154 NTSTATUS
155 STDCALL
156 NtCreateIoCompletion(
157 OUT PHANDLE IoCompletionHandle,
158 IN ACCESS_MASK DesiredAccess,
159 IN POBJECT_ATTRIBUTES ObjectAttributes,
160 IN ULONG NumberOfConcurrentThreads
161 )
162 {
163 PKQUEUE Queue;
164 NTSTATUS Status;
165
166 Status = ObCreateObject(ExGetPreviousMode(),
167 ExIoCompletionType,
168 ObjectAttributes,
169 ExGetPreviousMode(),
170 NULL,
171 sizeof(KQUEUE),
172 0,
173 0,
174 (PVOID*)&Queue);
175 if (!NT_SUCCESS(Status))
176 {
177 return Status;
178 }
179
180 Status = ObInsertObject ((PVOID)Queue,
181 NULL,
182 DesiredAccess,
183 0,
184 NULL,
185 IoCompletionHandle);
186 if (!NT_SUCCESS(Status))
187 {
188 ObDereferenceObject(Queue);
189 return Status;
190 }
191
192 KeInitializeQueue(Queue, NumberOfConcurrentThreads);
193 ObDereferenceObject(Queue);
194
195 return STATUS_SUCCESS;
196 /*
197
198 CompletionPort = NULL OR ExistingCompletionPort
199
200 */
201
202
203 }
204
205 /*
206 DesiredAccess:
207 ZERO
208 IO_COMPLETION_QUERY_STATE Query access
209 IO_COMPLETION_MODIFY_STATE Modify access
210 IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL
211
212 ObjectAttributes
213 OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes
214
215 Return Value
216 STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or
217 STATUS_OBJECT_NAME_NOT_FOUND.
218 */
219 NTSTATUS
220 STDCALL
221 NtOpenIoCompletion(
222 OUT PHANDLE IoCompletionHandle,
223 IN ACCESS_MASK DesiredAccess,
224 IN POBJECT_ATTRIBUTES ObjectAttributes
225 )
226 {
227 NTSTATUS Status;
228
229 Status = ObOpenObjectByName(ObjectAttributes,
230 ExIoCompletionType,
231 NULL,
232 UserMode,
233 DesiredAccess,
234 NULL,
235 IoCompletionHandle); //<- ???
236
237 return Status;
238 }
239
240
241 NTSTATUS
242 STDCALL
243 NtQueryIoCompletion(
244 IN HANDLE IoCompletionHandle,
245 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
246 OUT PVOID IoCompletionInformation,
247 IN ULONG IoCompletionInformationLength,
248 OUT PULONG ResultLength OPTIONAL
249 )
250 {
251 PKQUEUE Queue;
252 NTSTATUS Status;
253
254 if (IoCompletionInformationClass != IoCompletionBasicInformation)
255 {
256 return STATUS_INVALID_INFO_CLASS;
257 }
258 if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION))
259 {
260 return STATUS_INFO_LENGTH_MISMATCH;
261 }
262
263 Status = ObReferenceObjectByHandle( IoCompletionHandle,
264 IO_COMPLETION_QUERY_STATE,
265 ExIoCompletionType,
266 UserMode,
267 (PVOID*)&Queue,
268 NULL);
269 if (NT_SUCCESS(Status))
270 {
271 ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth =
272 Queue->Header.SignalState;
273
274 ObDereferenceObject(Queue);
275
276 if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
277 }
278
279 return Status;
280 }
281
282
283 /*
284 * Dequeues an I/O completion message from an I/O completion object
285 */
286 NTSTATUS
287 STDCALL
288 NtRemoveIoCompletion(
289 IN HANDLE IoCompletionHandle,
290 OUT PVOID *CompletionKey,
291 OUT PVOID *CompletionContext,
292 OUT PIO_STATUS_BLOCK IoStatusBlock,
293 IN PLARGE_INTEGER Timeout OPTIONAL
294 )
295 {
296 PKQUEUE Queue;
297 NTSTATUS Status;
298 PIO_COMPLETION_PACKET Packet;
299 PLIST_ENTRY ListEntry;
300
301 Status = ObReferenceObjectByHandle( IoCompletionHandle,
302 IO_COMPLETION_MODIFY_STATE,
303 ExIoCompletionType,
304 UserMode,
305 (PVOID*)&Queue,
306 NULL);
307 if (!NT_SUCCESS(Status))
308 {
309 return Status;
310 }
311
312 /*
313 Try 2 remove packet from queue. Wait (optionaly) if
314 no packet in queue or max num of threads allready running.
315 */
316
317 do {
318
319 ListEntry = KeRemoveQueue(Queue, UserMode, Timeout );
320
321 /* Nebbets book says nothing about NtRemoveIoCompletion returning STATUS_USER_APC,
322 and the umode equivalent GetQueuedCompletionStatus says nothing about this either,
323 so my guess it we should restart the operation. Need further investigation. -Gunnar
324 */
325
326 } while((NTSTATUS)ListEntry == STATUS_USER_APC);
327
328 ObDereferenceObject(Queue);
329
330 if ((NTSTATUS)ListEntry == STATUS_TIMEOUT)
331 {
332 return STATUS_TIMEOUT;
333 }
334
335 ASSERT(ListEntry);
336
337 Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
338
339 if (CompletionKey) *CompletionKey = Packet->Key;
340 if (CompletionContext) *CompletionContext = Packet->Context;
341 if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
342
343 ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
344
345 return STATUS_SUCCESS;
346 }
347
348
349 /*
350 ASSOSIERT MED FOB's IoCompletionContext
351
352 typedef struct _IO_COMPLETION_CONTEXT {
353 PVOID Port;
354 ULONG Key;
355 } IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
356
357 */
358
359
360 /*
361 * Queues an I/O completion message to an I/O completion object
362 */
363 NTSTATUS
364 STDCALL
365 NtSetIoCompletion(
366 IN HANDLE IoCompletionPortHandle,
367 IN PVOID CompletionKey,
368 IN PVOID CompletionContext,
369 IN NTSTATUS CompletionStatus,
370 IN ULONG CompletionInformation
371 )
372 {
373 NTSTATUS Status;
374 PKQUEUE Queue;
375
376 Status = ObReferenceObjectByHandle( IoCompletionPortHandle,
377 IO_COMPLETION_MODIFY_STATE,
378 ExIoCompletionType,
379 UserMode,
380 (PVOID*)&Queue,
381 NULL);
382 if (NT_SUCCESS(Status))
383 {
384 Status = IoSetIoCompletion(Queue, CompletionKey, CompletionContext,
385 CompletionStatus, CompletionInformation, TRUE);
386 ObDereferenceObject(Queue);
387 }
388
389 return Status;
390 }