- Add locking in IopDeleteFile, and only check for completion context or name if...
[reactos.git] / reactos / ntoskrnl / io / iomgr / irp.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/irp.c
5 * PURPOSE: IRP Handling Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 * Filip Navara (navaraf@reactos.org)
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* Undefine some macros we implement here */
18 #undef IoCallDriver
19 #undef IoCompleteRequest
20
21 /* PRIVATE FUNCTIONS ********************************************************/
22
23 VOID
24 NTAPI
25 IopFreeIrpKernelApc(IN PKAPC Apc,
26 IN PKNORMAL_ROUTINE *NormalRoutine,
27 IN PVOID *NormalContext,
28 IN PVOID *SystemArgument1,
29 IN PVOID *SystemArgument2)
30 {
31 /* Free the IRP */
32 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
33 }
34
35 VOID
36 NTAPI
37 IopAbortIrpKernelApc(IN PKAPC Apc)
38 {
39 /* Free the IRP */
40 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
41 }
42
43 NTSTATUS
44 NTAPI
45 IopCleanupFailedIrp(IN PFILE_OBJECT FileObject,
46 IN PKEVENT EventObject)
47 {
48 PAGED_CODE();
49
50 /* Dereference the event */
51 if (EventObject) ObDereferenceObject(EventObject);
52
53 /* If this was a file opened for synch I/O, then unlock it */
54 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
55
56 /* Now dereference it and return */
57 ObDereferenceObject(FileObject);
58 return STATUS_INSUFFICIENT_RESOURCES;
59 }
60
61 VOID
62 NTAPI
63 IopAbortInterruptedIrp(IN PKEVENT EventObject,
64 IN PIRP Irp)
65 {
66 KIRQL OldIrql;
67 BOOLEAN CancelResult;
68 LARGE_INTEGER Wait;
69 PAGED_CODE();
70
71 /* Raise IRQL to APC */
72 KeRaiseIrql(APC_LEVEL, &OldIrql);
73
74 /* Check if nobody completed it yet */
75 if (!KeReadStateEvent(EventObject))
76 {
77 /* First, cancel it */
78 CancelResult = IoCancelIrp(Irp);
79 KeLowerIrql(OldIrql);
80
81 /* Check if we cancelled it */
82 if (CancelResult)
83 {
84 /* Wait for the IRP to be cancelled */
85 Wait.QuadPart = -100000;
86 while (!KeReadStateEvent(EventObject))
87 {
88 /* Delay indefintely */
89 KeDelayExecutionThread(KernelMode, FALSE, &Wait);
90 }
91 }
92 else
93 {
94 /* No cancellation done, so wait for the I/O system to kill it */
95 KeWaitForSingleObject(EventObject,
96 Executive,
97 KernelMode,
98 FALSE,
99 NULL);
100 }
101 }
102 else
103 {
104 /* We got preempted, so give up */
105 KeLowerIrql(OldIrql);
106 }
107 }
108
109 VOID
110 NTAPI
111 IopRemoveThreadIrp(VOID)
112 {
113 KIRQL OldIrql;
114 PIRP DeadIrp;
115 PETHREAD IrpThread;
116 PLIST_ENTRY IrpEntry;
117 PIO_ERROR_LOG_PACKET ErrorLogEntry;
118 PDEVICE_OBJECT DeviceObject = NULL;
119 PIO_STACK_LOCATION IoStackLocation;
120
121 /* First, raise to APC to protect IrpList */
122 KeRaiseIrql(APC_LEVEL, &OldIrql);
123
124 /* Get the Thread and check the list */
125 IrpThread = PsGetCurrentThread();
126 if (IsListEmpty(&IrpThread->IrpList))
127 {
128 /* It got completed now, so quit */
129 KeLowerIrql(OldIrql);
130 return;
131 }
132
133 /* Get the misbehaving IRP */
134 IrpEntry = IrpThread->IrpList.Flink;
135 DeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
136 IOTRACE(IO_IRP_DEBUG,
137 "%s - Deassociating IRP %p for %p\n",
138 __FUNCTION__,
139 DeadIrp,
140 IrpThread);
141
142 /* Don't cancel the IRP if it's already been completed far */
143 if (DeadIrp->CurrentLocation == (DeadIrp->StackCount + 2))
144 {
145 /* Return */
146 KeLowerIrql(OldIrql);
147 return;
148 }
149
150 /* Disown the IRP! */
151 DeadIrp->Tail.Overlay.Thread = NULL;
152 RemoveHeadList(&IrpThread->IrpList);
153 InitializeListHead(&DeadIrp->ThreadListEntry);
154
155 /* Get the stack location and check if it's valid */
156 IoStackLocation = IoGetCurrentIrpStackLocation(DeadIrp);
157 if (DeadIrp->CurrentLocation <= DeadIrp->StackCount)
158 {
159 /* Get the device object */
160 DeviceObject = IoStackLocation->DeviceObject;
161 }
162
163 /* Lower IRQL now, since we have the pointers we need */
164 KeLowerIrql(OldIrql);
165
166 /* Check if we can send an Error Log Entry*/
167 if (DeviceObject)
168 {
169 /* Allocate an entry */
170 ErrorLogEntry = IoAllocateErrorLogEntry(DeviceObject,
171 sizeof(IO_ERROR_LOG_PACKET));
172 if (ErrorLogEntry)
173 {
174 /* Write the entry */
175 ErrorLogEntry->ErrorCode = 0xBAADF00D; /* FIXME */
176 IoWriteErrorLogEntry(ErrorLogEntry);
177 }
178 }
179 }
180
181 VOID
182 NTAPI
183 IopCleanupIrp(IN PIRP Irp,
184 IN PFILE_OBJECT FileObject)
185 {
186 PMDL Mdl;
187 IOTRACE(IO_IRP_DEBUG,
188 "%s - Cleaning IRP %p for %p\n",
189 __FUNCTION__,
190 Irp,
191 FileObject);
192
193 /* Check if there's an MDL */
194 while ((Mdl = Irp->MdlAddress))
195 {
196 /* Clear all of them */
197 Irp->MdlAddress = Mdl->Next;
198 IoFreeMdl(Mdl);
199 }
200
201 /* Check if the IRP has system buffer */
202 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
203 {
204 /* Free the buffer */
205 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
206 }
207
208 /* Check if this IRP has a user event, a file object, and is async */
209 if ((Irp->UserEvent) &&
210 !(Irp->Flags & IRP_SYNCHRONOUS_API) &&
211 (FileObject))
212 {
213 /* Derefernce the User Event */
214 ObDereferenceObject(Irp->UserEvent);
215 }
216
217 /* Dereference the File Object */
218 if (FileObject) ObDereferenceObject(FileObject);
219
220 /* Free the IRP */
221 IoFreeIrp(Irp);
222 }
223
224 VOID
225 NTAPI
226 IopCompleteRequest(IN PKAPC Apc,
227 IN PKNORMAL_ROUTINE* NormalRoutine,
228 IN PVOID* NormalContext,
229 IN PVOID* SystemArgument1,
230 IN PVOID* SystemArgument2)
231 {
232 PFILE_OBJECT FileObject;
233 PIRP Irp;
234 PMDL Mdl;
235 PVOID Port = NULL, Key = NULL;
236 BOOLEAN SignaledCreateRequest = FALSE;
237
238 /* Get data from the APC */
239 FileObject = (PFILE_OBJECT)*SystemArgument1;
240 Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
241 IOTRACE(IO_IRP_DEBUG,
242 "%s - Completing IRP %p for %p\n",
243 __FUNCTION__,
244 Irp,
245 FileObject);
246
247 /* Handle Buffered case first */
248 if (Irp->Flags & IRP_BUFFERED_IO)
249 {
250 /* Check if we have an input buffer and if we suceeded */
251 if ((Irp->Flags & IRP_INPUT_OPERATION) &&
252 (Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) &&
253 !(NT_ERROR(Irp->IoStatus.Status)))
254 {
255 /* Copy the buffer back to the user */
256 RtlCopyMemory(Irp->UserBuffer,
257 Irp->AssociatedIrp.SystemBuffer,
258 Irp->IoStatus.Information);
259 }
260
261 /* Also check if we should de-allocate it */
262 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
263 {
264 /* Deallocate it */
265 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
266 }
267 }
268
269 /* Now we got rid of these two... */
270 Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
271
272 /* Check if there's an MDL */
273 while ((Mdl = Irp->MdlAddress))
274 {
275 /* Clear all of them */
276 Irp->MdlAddress = Mdl->Next;
277 IoFreeMdl(Mdl);
278 }
279
280 /*
281 * Check if either the request was completed without any errors
282 * (but warnings are OK!), or if it was completed with an error, but
283 * did return from a pending I/O Operation and is not synchronous.
284 */
285 if ((!NT_ERROR(Irp->IoStatus.Status)) ||
286 (NT_ERROR(Irp->IoStatus.Status) &&
287 (Irp->PendingReturned) &&
288 !(IsIrpSynchronous(Irp, FileObject))))
289 {
290 /* Get any information we need from the FO before we kill it */
291 if ((FileObject) && (FileObject->CompletionContext))
292 {
293 /* Save Completion Data */
294 Port = FileObject->CompletionContext->Port;
295 Key = FileObject->CompletionContext->Key;
296 }
297
298 /* Use SEH to make sure we don't write somewhere invalid */
299 _SEH_TRY
300 {
301 /* Save the IOSB Information */
302 *Irp->UserIosb = Irp->IoStatus;
303 }
304 _SEH_HANDLE
305 {
306 /* Ignore any error */
307 }
308 _SEH_END;
309
310 /* Check if we have an event or a file object */
311 if (Irp->UserEvent)
312 {
313 /* At the very least, this is a PKEVENT, so signal it always */
314 KeSetEvent(Irp->UserEvent, 0, FALSE);
315
316 /* Check if we also have a File Object */
317 if (FileObject)
318 {
319 /*
320 * Now, if this is a Synch I/O File Object, then this event is
321 * NOT an actual Executive Event, so we won't dereference it,
322 * and instead, we will signal the File Object
323 */
324 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
325 {
326 /* Signal the file object and set the status */
327 KeSetEvent(&FileObject->Event, 0, FALSE);
328 FileObject->FinalStatus = Irp->IoStatus.Status;
329 }
330
331 /*
332 * This could also be a create operation, in which case we want
333 * to make sure there's no APC fired.
334 */
335 if (Irp->Flags & IRP_CREATE_OPERATION)
336 {
337 /* Clear the APC Routine and remmeber this */
338 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
339 SignaledCreateRequest = TRUE;
340 }
341 }
342 }
343 else if (FileObject)
344 {
345 /* Signal the file object and set the status */
346 KeSetEvent(&FileObject->Event, 0, FALSE);
347 FileObject->FinalStatus = Irp->IoStatus.Status;
348 }
349
350 /* Now that we've signaled the events, de-associate the IRP */
351 RemoveEntryList(&Irp->ThreadListEntry);
352 InitializeListHead(&Irp->ThreadListEntry);
353
354 /* Now check if a User APC Routine was requested */
355 if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
356 {
357 /* Initialize it */
358 KeInitializeApc(&Irp->Tail.Apc,
359 KeGetCurrentThread(),
360 CurrentApcEnvironment,
361 IopFreeIrpKernelApc,
362 IopAbortIrpKernelApc,
363 (PKNORMAL_ROUTINE)Irp->
364 Overlay.AsynchronousParameters.UserApcRoutine,
365 Irp->RequestorMode,
366 Irp->
367 Overlay.AsynchronousParameters.UserApcContext);
368
369 /* Queue it */
370 KeInsertQueueApc(&Irp->Tail.Apc, Irp->UserIosb, NULL, 2);
371 }
372 else if ((Port) &&
373 (Irp->Overlay.AsynchronousParameters.UserApcContext))
374 {
375 /* We have an I/O Completion setup... create the special Overlay */
376 Irp->Tail.CompletionKey = Key;
377 Irp->Tail.Overlay.PacketType = IrpCompletionPacket;
378 KeInsertQueue(Port, &Irp->Tail.Overlay.ListEntry);
379 }
380 else
381 {
382 /* Free the IRP since we don't need it anymore */
383 IoFreeIrp(Irp);
384 }
385
386 /* Check if we have a file object that wasn't part of a create */
387 if ((FileObject) && !(SignaledCreateRequest))
388 {
389 /* Dereference it, since it's not needed anymore either */
390 ObDereferenceObject(FileObject);
391 }
392 }
393 else
394 {
395 /*
396 * Either we didn't return from the request, or we did return but this
397 * request was synchronous.
398 */
399 if ((Irp->PendingReturned) && (FileObject))
400 {
401 /* So we did return with a synch operation, was it the IRP? */
402 if (Irp->Flags & IRP_SYNCHRONOUS_API)
403 {
404 /* Yes, this IRP was synchronous, so retrn the I/O Status */
405 *Irp->UserIosb = Irp->IoStatus;
406
407 /* Now check if the user gave an event */
408 if (Irp->UserEvent)
409 {
410 /* Signal it */
411 KeSetEvent(Irp->UserEvent, 0, FALSE);
412 }
413 else
414 {
415 /* No event was given, so signal the FO instead */
416 KeSetEvent(&FileObject->Event, 0, FALSE);
417 }
418 }
419 else
420 {
421 /*
422 * It's not the IRP that was synchronous, it was the FO
423 * that was opened this way. Signal its event.
424 */
425 FileObject->FinalStatus = Irp->IoStatus.Status;
426 KeSetEvent(&FileObject->Event, 0, FALSE);
427 }
428 }
429
430 /* Now that we got here, we do this for incomplete I/Os as well */
431 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
432 {
433 /* Dereference the File Object unless this was a create */
434 ObDereferenceObject(FileObject);
435 }
436
437 /*
438 * Check if this was an Executive Event (remember that we know this
439 * by checking if the IRP is synchronous)
440 */
441 if ((Irp->UserEvent) &&
442 (FileObject) &&
443 !(Irp->Flags & IRP_SYNCHRONOUS_API))
444 {
445 /* This isn't a PKEVENT, so dereference it */
446 ObDereferenceObject(Irp->UserEvent);
447 }
448
449 /* Now that we've signaled the events, de-associate the IRP */
450 RemoveEntryList(&Irp->ThreadListEntry);
451 InitializeListHead(&Irp->ThreadListEntry);
452
453 /* Free the IRP as well */
454 IoFreeIrp(Irp);
455 }
456 }
457
458 /* FUNCTIONS *****************************************************************/
459
460 /*
461 * @implemented
462 */
463 PIRP
464 NTAPI
465 IoAllocateIrp(IN CCHAR StackSize,
466 IN BOOLEAN ChargeQuota)
467 {
468 PIRP Irp = NULL;
469 USHORT Size = IoSizeOfIrp(StackSize);
470 PKPRCB Prcb;
471 UCHAR Flags = 0;
472 PNPAGED_LOOKASIDE_LIST List = NULL;
473 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
474
475 /* Figure out which Lookaside List to use */
476 if ((StackSize <= 8) && (ChargeQuota == FALSE))
477 {
478 /* Set Fixed Size Flag */
479 Flags = IRP_ALLOCATED_FIXED_SIZE;
480
481 /* See if we should use big list */
482 if (StackSize != 1)
483 {
484 Size = IoSizeOfIrp(8);
485 ListType = LookasideLargeIrpList;
486 }
487
488 /* Get the PRCB */
489 Prcb = KeGetCurrentPrcb();
490
491 /* Get the P List First */
492 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
493
494 /* Attempt allocation */
495 List->L.TotalAllocates++;
496 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
497
498 /* Check if the P List failed */
499 if (!Irp)
500 {
501 /* Let the balancer know */
502 List->L.AllocateMisses++;
503
504 /* Try the L List */
505 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
506 List->L.TotalAllocates++;
507 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
508 }
509 }
510
511 /* Check if we have to use the pool */
512 if (!Irp)
513 {
514 /* Did we try lookaside and fail? */
515 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
516
517 /* Check if we shoudl charge quota */
518 if (ChargeQuota)
519 {
520 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
521 /* FIXME */
522 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
523 }
524 else
525 {
526 /* Allocate the IRP With no Quota charge */
527 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
528 }
529
530 /* Make sure it was sucessful */
531 if (!Irp) return(NULL);
532 }
533 else
534 {
535 /* We have an IRP from Lookaside */
536 Flags |= IRP_LOOKASIDE_ALLOCATION;
537 }
538
539 /* Set Flag */
540 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
541
542 /* Now Initialize it */
543 IoInitializeIrp(Irp, Size, StackSize);
544
545 /* Set the Allocation Flags */
546 Irp->AllocationFlags = Flags;
547
548 /* Return it */
549 IOTRACE(IO_IRP_DEBUG,
550 "%s - Allocated IRP %p with allocation flags %lx\n",
551 __FUNCTION__,
552 Irp,
553 Flags);
554 return Irp;
555 }
556
557 /*
558 * @implemented
559 */
560 PIRP
561 NTAPI
562 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction,
563 IN PDEVICE_OBJECT DeviceObject,
564 IN PVOID Buffer,
565 IN ULONG Length,
566 IN PLARGE_INTEGER StartingOffset,
567 IN PIO_STATUS_BLOCK IoStatusBlock)
568 {
569 PIRP Irp;
570 PIO_STACK_LOCATION StackPtr;
571
572 /* Allocate IRP */
573 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
574 if (!Irp) return Irp;
575
576 /* Get the Stack */
577 StackPtr = IoGetNextIrpStackLocation(Irp);
578
579 /* Write the Major function and then deal with it */
580 StackPtr->MajorFunction = (UCHAR)MajorFunction;
581
582 /* Do not handle the following here */
583 if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
584 (MajorFunction != IRP_MJ_SHUTDOWN) &&
585 (MajorFunction != IRP_MJ_PNP) &&
586 (MajorFunction != IRP_MJ_POWER))
587 {
588 /* Check if this is Buffered IO */
589 if (DeviceObject->Flags & DO_BUFFERED_IO)
590 {
591 /* Allocate the System Buffer */
592 Irp->AssociatedIrp.SystemBuffer =
593 ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF);
594 if (!Irp->AssociatedIrp.SystemBuffer)
595 {
596 /* Free the IRP and fail */
597 IoFreeIrp(Irp);
598 return NULL;
599 }
600
601 /* Set flags */
602 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
603
604 /* Handle special IRP_MJ_WRITE Case */
605 if (MajorFunction == IRP_MJ_WRITE)
606 {
607 /* Copy the buffer data */
608 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
609 }
610 else
611 {
612 /* Set the Input Operation flag and set this as a User Buffer */
613 Irp->Flags |= IRP_INPUT_OPERATION;
614 Irp->UserBuffer = Buffer;
615 }
616 }
617 else if (DeviceObject->Flags & DO_DIRECT_IO)
618 {
619 /* Use an MDL for Direct I/O */
620 Irp->MdlAddress = IoAllocateMdl(Buffer,
621 Length,
622 FALSE,
623 FALSE,
624 NULL);
625 if (!Irp->MdlAddress)
626 {
627 /* Free the IRP and fail */
628 IoFreeIrp(Irp);
629 return NULL;
630 }
631
632 /* Probe and Lock */
633 _SEH_TRY
634 {
635 /* Do the probe */
636 MmProbeAndLockPages(Irp->MdlAddress,
637 KernelMode,
638 MajorFunction == IRP_MJ_READ ?
639 IoWriteAccess : IoReadAccess);
640 }
641 _SEH_HANDLE
642 {
643 /* Free the IRP and its MDL */
644 IoFreeMdl(Irp->MdlAddress);
645 IoFreeIrp(Irp);
646 Irp = NULL;
647 }
648 _SEH_END;
649
650 /* This is how we know if we failed during the probe */
651 if (!Irp) return NULL;
652 }
653 else
654 {
655 /* Neither, use the buffer */
656 Irp->UserBuffer = Buffer;
657 }
658
659 /* Check if this is a read */
660 if (MajorFunction == IRP_MJ_READ)
661 {
662 /* Set the parameters for a read */
663 StackPtr->Parameters.Read.Length = Length;
664 StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
665 }
666 else if (MajorFunction == IRP_MJ_WRITE)
667 {
668 /* Otherwise, set write parameters */
669 StackPtr->Parameters.Write.Length = Length;
670 StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
671 }
672 }
673
674 /* Set the Current Thread and IOSB */
675 Irp->UserIosb = IoStatusBlock;
676 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
677
678 /* Set the Status Block after all is done */
679 IOTRACE(IO_IRP_DEBUG,
680 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
681 __FUNCTION__,
682 Irp,
683 MajorFunction,
684 Buffer,
685 DeviceObject);
686 return Irp;
687 }
688
689 /*
690 * @implemented
691 */
692 PIRP
693 NTAPI
694 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode,
695 IN PDEVICE_OBJECT DeviceObject,
696 IN PVOID InputBuffer,
697 IN ULONG InputBufferLength,
698 IN PVOID OutputBuffer,
699 IN ULONG OutputBufferLength,
700 IN BOOLEAN InternalDeviceIoControl,
701 IN PKEVENT Event,
702 IN PIO_STATUS_BLOCK IoStatusBlock)
703 {
704 PIRP Irp;
705 PIO_STACK_LOCATION StackPtr;
706 ULONG BufferLength;
707
708 /* Allocate IRP */
709 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
710 if (!Irp) return Irp;
711
712 /* Get the Stack */
713 StackPtr = IoGetNextIrpStackLocation(Irp);
714
715 /* Set the DevCtl Type */
716 StackPtr->MajorFunction = InternalDeviceIoControl ?
717 IRP_MJ_INTERNAL_DEVICE_CONTROL :
718 IRP_MJ_DEVICE_CONTROL;
719
720 /* Set the IOCTL Data */
721 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
722 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
723 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
724 OutputBufferLength;
725
726 /* Handle the Methods */
727 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
728 {
729 /* Buffered I/O */
730 case METHOD_BUFFERED:
731
732 /* Select the right Buffer Length */
733 BufferLength = InputBufferLength > OutputBufferLength ?
734 InputBufferLength : OutputBufferLength;
735
736 /* Make sure there is one */
737 if (BufferLength)
738 {
739 /* Allocate the System Buffer */
740 Irp->AssociatedIrp.SystemBuffer =
741 ExAllocatePoolWithTag(NonPagedPool,
742 BufferLength,
743 TAG_SYS_BUF);
744 if (!Irp->AssociatedIrp.SystemBuffer)
745 {
746 /* Free the IRP and fail */
747 IoFreeIrp(Irp);
748 return NULL;
749 }
750
751 /* Check if we got a buffer */
752 if (InputBuffer)
753 {
754 /* Copy into the System Buffer */
755 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
756 InputBuffer,
757 InputBufferLength);
758 }
759
760 /* Write the flags */
761 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
762 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
763
764 /* Save the Buffer */
765 Irp->UserBuffer = OutputBuffer;
766 }
767 else
768 {
769 /* Clear the Flags and Buffer */
770 Irp->Flags = 0;
771 Irp->UserBuffer = NULL;
772 }
773 break;
774
775 /* Direct I/O */
776 case METHOD_IN_DIRECT:
777 case METHOD_OUT_DIRECT:
778
779 /* Check if we got an input buffer */
780 if (InputBuffer)
781 {
782 /* Allocate the System Buffer */
783 Irp->AssociatedIrp.SystemBuffer =
784 ExAllocatePoolWithTag(NonPagedPool,
785 InputBufferLength,
786 TAG_SYS_BUF);
787 if (!Irp->AssociatedIrp.SystemBuffer)
788 {
789 /* Free the IRP and fail */
790 IoFreeIrp(Irp);
791 return NULL;
792 }
793
794 /* Copy into the System Buffer */
795 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
796 InputBuffer,
797 InputBufferLength);
798
799 /* Write the flags */
800 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
801 }
802 else
803 {
804 Irp->Flags = 0;
805 }
806
807 /* Check if we got an output buffer */
808 if (OutputBuffer)
809 {
810 /* Allocate the System Buffer */
811 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
812 OutputBufferLength,
813 FALSE,
814 FALSE,
815 Irp);
816 if (!Irp->MdlAddress)
817 {
818 /* Free the IRP and fail */
819 IoFreeIrp(Irp);
820 return NULL;
821 }
822
823 /* Probe and Lock */
824 _SEH_TRY
825 {
826 /* Do the probe */
827 MmProbeAndLockPages(Irp->MdlAddress,
828 KernelMode,
829 IO_METHOD_FROM_CTL_CODE(IoControlCode) ==
830 METHOD_IN_DIRECT ?
831 IoReadAccess : IoWriteAccess);
832 }
833 _SEH_HANDLE
834 {
835 /* Free the MDL */
836 IoFreeMdl(Irp->MdlAddress);
837
838 /* Free the input buffer and IRP */
839 if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer);
840 IoFreeIrp(Irp);
841 Irp = NULL;
842 }
843 _SEH_END;
844
845 /* This is how we know if probing failed */
846 if (!Irp) return NULL;
847 }
848 break;
849
850 case METHOD_NEITHER:
851
852 /* Just save the Buffer */
853 Irp->UserBuffer = OutputBuffer;
854 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
855 }
856
857 /* Now write the Event and IoSB */
858 Irp->UserIosb = IoStatusBlock;
859 Irp->UserEvent = Event;
860
861 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
862 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
863 IoQueueThreadIrp(Irp);
864
865 /* Return the IRP */
866 IOTRACE(IO_IRP_DEBUG,
867 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
868 __FUNCTION__,
869 Irp,
870 IoControlCode,
871 InputBuffer,
872 OutputBuffer,
873 DeviceObject);
874 return Irp;
875 }
876
877 /*
878 * @implemented
879 */
880 PIRP
881 NTAPI
882 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction,
883 IN PDEVICE_OBJECT DeviceObject,
884 IN PVOID Buffer,
885 IN ULONG Length,
886 IN PLARGE_INTEGER StartingOffset,
887 IN PKEVENT Event,
888 IN PIO_STATUS_BLOCK IoStatusBlock)
889 {
890 PIRP Irp;
891
892 /* Do the big work to set up the IRP */
893 Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
894 DeviceObject,
895 Buffer,
896 Length,
897 StartingOffset,
898 IoStatusBlock );
899 if (!Irp) return NULL;
900
901 /* Set the Event which makes it Syncronous */
902 Irp->UserEvent = Event;
903
904 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
905 IoQueueThreadIrp(Irp);
906 return Irp;
907 }
908
909 /*
910 * @implemented
911 */
912 BOOLEAN
913 NTAPI
914 IoCancelIrp(IN PIRP Irp)
915 {
916 KIRQL OldIrql;
917 PDRIVER_CANCEL CancelRoutine;
918 IOTRACE(IO_IRP_DEBUG,
919 "%s - Canceling IRP %p\n",
920 __FUNCTION__,
921 Irp);
922 ASSERT(Irp->Type == IO_TYPE_IRP);
923
924 /* Acquire the cancel lock and cancel the IRP */
925 IoAcquireCancelSpinLock(&OldIrql);
926 Irp->Cancel = TRUE;
927
928 /* Clear the cancel routine and get the old one */
929 CancelRoutine = IoSetCancelRoutine(Irp, NULL);
930 if (CancelRoutine)
931 {
932 /* We had a routine, make sure the IRP isn't completed */
933 if (Irp->CurrentLocation > (Irp->StackCount + 1))
934 {
935 /* It is, bugcheck */
936 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
937 (ULONG_PTR)Irp,
938 0,
939 0,
940 0);
941 }
942
943 /* Set the cancel IRQL And call the routine */
944 Irp->CancelIrql = OldIrql;
945 CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
946 return TRUE;
947 }
948
949 /* Otherwise, release the cancel lock and fail */
950 IoReleaseCancelSpinLock(OldIrql);
951 return FALSE;
952 }
953
954 /*
955 * @implemented
956 */
957 VOID
958 NTAPI
959 IoCancelThreadIo(IN PETHREAD Thread)
960 {
961 KIRQL OldIrql;
962 ULONG Retries = 3000;
963 LARGE_INTEGER Interval;
964 PLIST_ENTRY ListHead, NextEntry;
965 PIRP Irp;
966 IOTRACE(IO_IRP_DEBUG,
967 "%s - Canceling IRPs for Thread %p\n",
968 __FUNCTION__,
969 Thread);
970
971 /* Raise to APC to protect the IrpList */
972 OldIrql = KfRaiseIrql(APC_LEVEL);
973
974 /* Start by cancelling all the IRPs in the current thread queue. */
975 ListHead = &Thread->IrpList;
976 NextEntry = ListHead->Flink;
977 while (ListHead != NextEntry)
978 {
979 /* Get the IRP */
980 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
981
982 /* Cancel it */
983 IoCancelIrp(Irp);
984
985 /* Move to the next entry */
986 NextEntry = NextEntry->Flink;
987 }
988
989 /* Wait 100 milliseconds */
990 Interval.QuadPart = -1000000;
991
992 /* Wait till all the IRPs are completed or cancelled. */
993 while (!IsListEmpty(&Thread->IrpList))
994 {
995 /* Now we can lower */
996 KfLowerIrql(OldIrql);
997
998 /* Wait a short while and then look if all our IRPs were completed. */
999 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1000
1001 /*
1002 * Don't stay here forever if some broken driver doesn't complete
1003 * the IRP.
1004 */
1005 if (!(Retries--)) IopRemoveThreadIrp();
1006
1007 /* Raise the IRQL Again */
1008 OldIrql = KfRaiseIrql(APC_LEVEL);
1009 }
1010
1011 /* We're done, lower the IRQL */
1012 KfLowerIrql(OldIrql);
1013 }
1014
1015 /*
1016 * @implemented
1017 */
1018 NTSTATUS
1019 NTAPI
1020 IoCallDriver(IN PDEVICE_OBJECT DeviceObject,
1021 IN PIRP Irp)
1022 {
1023 /* Call fast call */
1024 return IofCallDriver(DeviceObject, Irp);
1025 }
1026
1027 /*
1028 * @implemented
1029 */
1030 VOID
1031 NTAPI
1032 IoCompleteRequest(IN PIRP Irp,
1033 IN CCHAR PriorityBoost)
1034 {
1035 /* Call the fastcall */
1036 IofCompleteRequest(Irp, PriorityBoost);
1037 }
1038
1039 /*
1040 * @implemented
1041 */
1042 VOID
1043 NTAPI
1044 IoEnqueueIrp(IN PIRP Irp)
1045 {
1046 /* This is the same as calling IoQueueThreadIrp */
1047 IoQueueThreadIrp(Irp);
1048 }
1049
1050 /*
1051 * @implemented
1052 */
1053 NTSTATUS
1054 FASTCALL
1055 IofCallDriver(IN PDEVICE_OBJECT DeviceObject,
1056 IN PIRP Irp)
1057 {
1058 PDRIVER_OBJECT DriverObject;
1059 PIO_STACK_LOCATION Param;
1060
1061 /* Get the Driver Object */
1062 DriverObject = DeviceObject->DriverObject;
1063
1064 /* Decrease the current location and check if */
1065 Irp->CurrentLocation--;
1066 if (Irp->CurrentLocation <= 0)
1067 {
1068 /* This IRP ran out of stack, bugcheck */
1069 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
1070 }
1071
1072 /* Now update the stack location */
1073 Param = IoGetNextIrpStackLocation(Irp);
1074 Irp->Tail.Overlay.CurrentStackLocation = Param;
1075
1076 /* Get the Device Object */
1077 Param->DeviceObject = DeviceObject;
1078
1079 /* Call it */
1080 return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject,
1081 Irp);
1082 }
1083
1084 /*
1085 * @implemented
1086 */
1087 VOID
1088 FASTCALL
1089 IofCompleteRequest(IN PIRP Irp,
1090 IN CCHAR PriorityBoost)
1091 {
1092 PIO_STACK_LOCATION StackPtr;
1093 PDEVICE_OBJECT DeviceObject;
1094 PFILE_OBJECT FileObject;
1095 PETHREAD Thread;
1096 NTSTATUS Status;
1097 PMDL Mdl;
1098 ULONG MasterIrpCount;
1099 PIRP MasterIrp;
1100 IOTRACE(IO_IRP_DEBUG,
1101 "%s - Completing IRP %p\n",
1102 __FUNCTION__,
1103 Irp);
1104
1105 /* Make sure this IRP isn't getting completed more then once */
1106 if ((Irp->CurrentLocation) > (Irp->StackCount + 1))
1107 {
1108 /* Bugcheck */
1109 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);
1110 }
1111
1112 /* Some sanity checks */
1113 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
1114 ASSERT(!Irp->CancelRoutine);
1115 ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1116
1117 /* Get the Current Stack and skip it */
1118 StackPtr = IoGetCurrentIrpStackLocation(Irp);
1119 IoSkipCurrentIrpStackLocation(Irp);
1120
1121 /* Loop the Stacks and complete the IRPs */
1122 do
1123 {
1124 /* Set Pending Returned */
1125 Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
1126
1127 /* Check if there is a Completion Routine to Call */
1128 if ((NT_SUCCESS(Irp->IoStatus.Status) &&
1129 (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
1130 (!NT_SUCCESS(Irp->IoStatus.Status) &&
1131 (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
1132 (Irp->Cancel && (StackPtr->Control & SL_INVOKE_ON_CANCEL)))
1133 {
1134 /* Check for highest-level device completion routines */
1135 if (Irp->CurrentLocation == (Irp->StackCount + 1))
1136 {
1137 /* Clear the DO, since the current stack location is invalid */
1138 DeviceObject = NULL;
1139 }
1140 else
1141 {
1142 /* Otherwise, return the real one */
1143 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
1144 }
1145
1146 /* Call the completion routine */
1147 Status = StackPtr->CompletionRoutine(DeviceObject,
1148 Irp,
1149 StackPtr->Context);
1150
1151 /* Don't touch the Packet in this case, since it might be gone! */
1152 if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
1153 }
1154 else
1155 {
1156 /* Otherwise, check if this is a completed IRP */
1157 if ((Irp->CurrentLocation <= Irp->StackCount) &&
1158 (Irp->PendingReturned))
1159 {
1160 /* Mark it as pending */
1161 IoMarkIrpPending(Irp);
1162 }
1163 }
1164
1165 /* Move to next stack location and pointer */
1166 IoSkipCurrentIrpStackLocation(Irp);
1167 StackPtr++;
1168 } while (Irp->CurrentLocation <= (Irp->StackCount + 1));
1169
1170 /* Check if the IRP is an associated IRP */
1171 if (Irp->Flags & IRP_ASSOCIATED_IRP)
1172 {
1173 /* This should never happen! */
1174 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1175
1176 /* Get the master IRP and count */
1177 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1178 MasterIrpCount = InterlockedDecrement(&MasterIrp->
1179 AssociatedIrp.IrpCount);
1180
1181 /* Set the thread of this IRP as the master's */
1182 Irp->Tail.Overlay.Thread = MasterIrp->Tail.Overlay.Thread;
1183
1184 /* Free the MDLs */
1185 while ((Mdl = Irp->MdlAddress))
1186 {
1187 /* Go to the next one */
1188 Irp->MdlAddress = Mdl->Next;
1189 IoFreeMdl(Mdl);
1190 }
1191
1192 /* Free the IRP itself */
1193 IoFreeIrp(Irp);
1194
1195 /* Complete the Master IRP */
1196 if (!MasterIrpCount) IofCompleteRequest(MasterIrp, PriorityBoost);
1197 return;
1198 }
1199
1200 /* Check if we have an auxiliary buffer */
1201 if (Irp->Tail.Overlay.AuxiliaryBuffer)
1202 {
1203 /* Free it */
1204 ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);
1205 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
1206 }
1207
1208 /* Check if this is a Paging I/O or Close Operation */
1209 if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION))
1210 {
1211 /* This should never happen! */
1212 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1213
1214 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1215 if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
1216 {
1217 /* Set the I/O Status and Signal the Event */
1218 *Irp->UserIosb = Irp->IoStatus;
1219 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
1220
1221 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1222 if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) IoFreeIrp(Irp);
1223 }
1224 else
1225 {
1226 #if 0
1227 /* Page 166 */
1228 KeInitializeApc(&Irp->Tail.Apc
1229 &Irp->Tail.Overlay.Thread->Tcb,
1230 Irp->ApcEnvironment,
1231 IopCompletePageWrite,
1232 NULL,
1233 NULL,
1234 KernelMode,
1235 NULL);
1236 KeInsertQueueApc(&Irp->Tail.Apc,
1237 NULL,
1238 NULL,
1239 PriorityBoost);
1240 #else
1241 /* Not implemented yet. */
1242 ASSERT(FALSE);
1243 #endif
1244 }
1245
1246 /* Get out of here */
1247 return;
1248 }
1249
1250 /* Unlock MDL Pages, page 167. */
1251 Mdl = Irp->MdlAddress;
1252 while (Mdl)
1253 {
1254 MmUnlockPages(Mdl);
1255 Mdl = Mdl->Next;
1256 }
1257
1258 /* Check if we should exit because of a Deferred I/O (page 168) */
1259 if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned))
1260 {
1261 /*
1262 * Return without queuing the completion APC, since the caller will
1263 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1264 */
1265 return;
1266 }
1267
1268 /* Get the thread and file object */
1269 Thread = Irp->Tail.Overlay.Thread;
1270 FileObject = Irp->Tail.Overlay.OriginalFileObject;
1271
1272 /* Make sure the IRP isn't cancelled */
1273 if (!Irp->Cancel)
1274 {
1275 /* Initialize the APC */
1276 KeInitializeApc(&Irp->Tail.Apc,
1277 &Thread->Tcb,
1278 Irp->ApcEnvironment,
1279 IopCompleteRequest,
1280 NULL,
1281 NULL,
1282 KernelMode,
1283 NULL);
1284
1285 /* Queue it */
1286 KeInsertQueueApc(&Irp->Tail.Apc,
1287 FileObject,
1288 NULL, /* This is used for REPARSE stuff */
1289 PriorityBoost);
1290 }
1291 else
1292 {
1293 /* The IRP just got cancelled... does a thread still own it? */
1294 Thread = Irp->Tail.Overlay.Thread;
1295 if (Thread)
1296 {
1297 /* Yes! There is still hope! Initialize the APC */
1298 KeInitializeApc(&Irp->Tail.Apc,
1299 &Thread->Tcb,
1300 Irp->ApcEnvironment,
1301 IopCompleteRequest,
1302 NULL,
1303 NULL,
1304 KernelMode,
1305 NULL);
1306
1307 /* Queue it */
1308 KeInsertQueueApc(&Irp->Tail.Apc,
1309 FileObject,
1310 NULL, /* This is used for REPARSE stuff */
1311 PriorityBoost);
1312 }
1313 else
1314 {
1315 /* Nothing left for us to do, kill it */
1316 IopCleanupIrp(Irp, FileObject);
1317 }
1318 }
1319 }
1320
1321 /*
1322 * @unimplemented
1323 */
1324 BOOLEAN
1325 NTAPI
1326 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
1327 IN PIRP Irp)
1328 {
1329 UNIMPLEMENTED;
1330 return FALSE;
1331 }
1332
1333 /*
1334 * @implemented
1335 */
1336 VOID
1337 NTAPI
1338 IoFreeIrp(IN PIRP Irp)
1339 {
1340 PNPAGED_LOOKASIDE_LIST List;
1341 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
1342 PKPRCB Prcb;
1343 IOTRACE(IO_IRP_DEBUG,
1344 "%s - Freeing IRPs %p\n",
1345 __FUNCTION__,
1346 Irp);
1347
1348 /* Make sure the Thread IRP list is empty and that it OK to free it */
1349 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1350 ASSERT(Irp->CurrentLocation >= Irp->StackCount);
1351
1352 /* If this was a pool alloc, free it with the pool */
1353 if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE))
1354 {
1355 /* Free it */
1356 ExFreePool(Irp);
1357 }
1358 else
1359 {
1360 /* Check if this was a Big IRP */
1361 if (Irp->StackCount != 1) ListType = LookasideLargeIrpList;
1362
1363 /* Get the PRCB */
1364 Prcb = KeGetCurrentPrcb();
1365
1366 /* Use the P List */
1367 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
1368 List->L.TotalFrees++;
1369
1370 /* Check if the Free was within the Depth or not */
1371 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1372 {
1373 /* Let the balancer know */
1374 List->L.FreeMisses++;
1375
1376 /* Use the L List */
1377 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
1378 List->L.TotalFrees++;
1379
1380 /* Check if the Free was within the Depth or not */
1381 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1382 {
1383 /* All lists failed, use the pool */
1384 List->L.FreeMisses++;
1385 ExFreePool(Irp);
1386 Irp = NULL;
1387 }
1388 }
1389
1390 /* The free was within the Depth */
1391 if (Irp)
1392 {
1393 InterlockedPushEntrySList(&List->L.ListHead,
1394 (PSINGLE_LIST_ENTRY)Irp);
1395 }
1396 }
1397 }
1398
1399 /*
1400 * @implemented
1401 */
1402 PEPROCESS NTAPI
1403 IoGetRequestorProcess(IN PIRP Irp)
1404 {
1405 return(Irp->Tail.Overlay.Thread->ThreadsProcess);
1406 }
1407
1408 /*
1409 * @implemented
1410 */
1411 ULONG
1412 NTAPI
1413 IoGetRequestorProcessId(IN PIRP Irp)
1414 {
1415 return (ULONG)(IoGetRequestorProcess(Irp)->UniqueProcessId);
1416 }
1417
1418 /*
1419 * @implemented
1420 */
1421 NTSTATUS
1422 NTAPI
1423 IoGetRequestorSessionId(IN PIRP Irp,
1424 OUT PULONG pSessionId)
1425 {
1426 /* Return the session */
1427 *pSessionId = IoGetRequestorProcess(Irp)->Session;
1428 return STATUS_SUCCESS;
1429 }
1430
1431 /*
1432 * @implemented
1433 */
1434 PIRP
1435 NTAPI
1436 IoGetTopLevelIrp(VOID)
1437 {
1438 return (PIRP)PsGetCurrentThread()->TopLevelIrp;
1439 }
1440
1441 /*
1442 * @implemented
1443 */
1444 VOID
1445 NTAPI
1446 IoInitializeIrp(IN PIRP Irp,
1447 IN USHORT PacketSize,
1448 IN CCHAR StackSize)
1449 {
1450 /* Clear it */
1451 IOTRACE(IO_IRP_DEBUG,
1452 "%s - Initializing IRP %p\n",
1453 __FUNCTION__,
1454 Irp);
1455 RtlZeroMemory(Irp, PacketSize);
1456
1457 /* Set the Header and other data */
1458 Irp->Type = IO_TYPE_IRP;
1459 Irp->Size = PacketSize;
1460 Irp->StackCount = StackSize;
1461 Irp->CurrentLocation = StackSize + 1;
1462 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
1463 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
1464
1465 /* Initialize the Thread List */
1466 InitializeListHead(&Irp->ThreadListEntry);
1467 }
1468
1469 /*
1470 * @implemented
1471 */
1472 BOOLEAN
1473 NTAPI
1474 IoIsOperationSynchronous(IN PIRP Irp)
1475 {
1476 /* Check the flags */
1477 if (((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) &&
1478 (!(Irp->Flags & IRP_PAGING_IO) &&
1479 !(Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO))) ||
1480 (Irp->Flags & IRP_SYNCHRONOUS_API) ||
1481 (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags &
1482 FO_SYNCHRONOUS_IO))
1483 {
1484 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1485 return TRUE;
1486 }
1487
1488 /* Otherwise, it is an asynchronous operation. */
1489 return FALSE;
1490 }
1491
1492 /*
1493 * @unimplemented
1494 */
1495 BOOLEAN
1496 NTAPI
1497 IoIsValidNameGraftingBuffer(IN PIRP Irp,
1498 IN PREPARSE_DATA_BUFFER ReparseBuffer)
1499 {
1500 UNIMPLEMENTED;
1501 return FALSE;
1502 }
1503
1504 /*
1505 * @implemented
1506 */
1507 PIRP
1508 NTAPI
1509 IoMakeAssociatedIrp(IN PIRP Irp,
1510 IN CCHAR StackSize)
1511 {
1512 PIRP AssocIrp;
1513 IOTRACE(IO_IRP_DEBUG,
1514 "%s - Associating IRP %p\n",
1515 __FUNCTION__,
1516 Irp);
1517
1518 /* Allocate the IRP */
1519 AssocIrp = IoAllocateIrp(StackSize, FALSE);
1520 if (!AssocIrp) return NULL;
1521
1522 /* Set the Flags */
1523 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
1524
1525 /* Set the Thread */
1526 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
1527
1528 /* Associate them */
1529 AssocIrp->AssociatedIrp.MasterIrp = Irp;
1530 return AssocIrp;
1531 }
1532
1533 /*
1534 * @implemented
1535 */
1536 VOID
1537 NTAPI
1538 IoQueueThreadIrp(IN PIRP Irp)
1539 {
1540 IOTRACE(IO_IRP_DEBUG,
1541 "%s - Queueing IRP %p\n",
1542 __FUNCTION__,
1543 Irp);
1544
1545 /* Use our inlined routine */
1546 IopQueueIrpToThread(Irp);
1547 }
1548
1549 /*
1550 * @implemented
1551 * Reference: Chris Cant's "Writing WDM Device Drivers"
1552 */
1553 VOID
1554 NTAPI
1555 IoReuseIrp(IN OUT PIRP Irp,
1556 IN NTSTATUS Status)
1557 {
1558 UCHAR AllocationFlags;
1559 IOTRACE(IO_IRP_DEBUG,
1560 "%s - Reusing IRP %p\n",
1561 __FUNCTION__,
1562 Irp);
1563
1564 /* Make sure it's OK to reuse it */
1565 ASSERT(!Irp->CancelRoutine);
1566 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1567
1568 /* Get the old flags */
1569 AllocationFlags = Irp->AllocationFlags;
1570
1571 /* Reinitialize the IRP */
1572 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
1573
1574 /* Duplicate the data */
1575 Irp->IoStatus.Status = Status;
1576 Irp->AllocationFlags = AllocationFlags;
1577 }
1578
1579 /*
1580 * @implemented
1581 */
1582 VOID
1583 NTAPI
1584 IoSetTopLevelIrp(IN PIRP Irp)
1585 {
1586 /* Set the IRP */
1587 PsGetCurrentThread()->TopLevelIrp = (ULONG)Irp;
1588 }
1589
1590 /* EOF */