convert DefaultSetInfoBufferCheck and DefaultQueryInfoBufferCheck to inlined functions
[reactos.git] / reactos / ntoskrnl / io / iocomp.c
index dddc777..946dfb4 100644 (file)
 /*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
- * FILE:            ntoskrnl/ke/iocomp.c
- * PURPOSE:         
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                  Created 22/05/98
-                   Changed NtQueryIoCompletion 
+ * FILE:            ntoskrnl/io/iocomp.c
+ * PURPOSE:         No purpose listed.
+ *
+ * PROGRAMMERS:     David Welch (welch@mcmail.com)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <limits.h>
-#define NTOS_MODE_KERNEL
-#include <ntos.h>
-//#include <ntos/synch.h>
-#include <internal/io.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
-#define IOC_TAG   TAG('I', 'O', 'C', 'T')   
-
-POBJECT_TYPE ExIoCompletionType;
+POBJECT_TYPE IoCompletionType;
 
-NPAGED_LOOKASIDE_LIST  IoCompletionPacketLookaside;
+NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
 
-static GENERIC_MAPPING ExIoCompletionMapping = 
+static GENERIC_MAPPING IopCompletionMapping =
 {
-   STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE,
-   STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE,
-   STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
-   IO_COMPLETION_ALL_ACCESS
+    STANDARD_RIGHTS_READ    | IO_COMPLETION_QUERY_STATE,
+    STANDARD_RIGHTS_WRITE   | IO_COMPLETION_MODIFY_STATE,
+    STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
+    IO_COMPLETION_ALL_ACCESS
+};
+
+static const INFORMATION_CLASS_INFO IoCompletionInfoClass[] = {
+
+     /* IoCompletionBasicInformation */
+    ICI_SQ_SAME( sizeof(IO_COMPLETION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ),
 };
 
 /* FUNCTIONS *****************************************************************/
 
-NTSTATUS 
+VOID
 STDCALL
-NtpCreateIoCompletion(
-   PVOID                ObjectBody,
-   PVOID                Parent,
-   PWSTR                RemainingPath,
-   POBJECT_ATTRIBUTES   ObjectAttributes
-   )
+IopFreeIoCompletionPacket(PIO_COMPLETION_PACKET Packet)
 {
-   DPRINT("NtpCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-      ObjectBody, Parent, RemainingPath);
-
-   if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
-   {
-      return STATUS_UNSUCCESSFUL;
-   }
-
-   return STATUS_SUCCESS;
+    PKPRCB Prcb = KeGetCurrentPrcb();
+    PNPAGED_LOOKASIDE_LIST List;
+    
+    /* Use the P List */
+    List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].P;
+    List->L.TotalFrees++;
+        
+    /* Check if the Free was within the Depth or not */
+    if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
+    {
+        /* Let the balancer know */
+        List->L.FreeMisses++;
+            
+        /* Use the L List */
+        List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].L;
+        List->L.TotalFrees++;
+
+        /* Check if the Free was within the Depth or not */
+        if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
+        {            
+            /* All lists failed, use the pool */
+            List->L.FreeMisses++;
+            ExFreePool(Packet);
+        }
+    }
+        
+    /* The free was within dhe Depth */
+    InterlockedPushEntrySList(&List->L.ListHead, (PSINGLE_LIST_ENTRY)Packet);
 }
 
-VOID STDCALL
-NtpDeleteIoCompletion(PVOID ObjectBody)
+VOID
+STDCALL
+IopDeleteIoCompletion(PVOID ObjectBody)
 {
-   PKQUEUE Queue = ObjectBody;
-
-   DPRINT("NtpDeleteIoCompletion()\n");
-
-   KeRundownQueue(Queue);
+    PKQUEUE Queue = ObjectBody;
+    PLIST_ENTRY FirstEntry;
+    PLIST_ENTRY CurrentEntry;
+    PIRP Irp;
+    PIO_COMPLETION_PACKET Packet;
+
+    DPRINT("IopDeleteIoCompletion()\n");
+
+    /* Rundown the Queue */
+    FirstEntry = KeRundownQueue(Queue);
+
+    /* Clean up the IRPs */
+    if (FirstEntry) {
+
+        CurrentEntry = FirstEntry;
+        do {
+
+            /* Get the Packet */
+            Packet = CONTAINING_RECORD(CurrentEntry, IO_COMPLETION_PACKET, ListEntry);
+
+            /* Go to next Entry */
+            CurrentEntry = CurrentEntry->Flink;
+
+            /* Check if it's part of an IRP, or a separate packet */
+            if (Packet->PacketType == IrpCompletionPacket)
+            {
+                /* Get the IRP and free it */
+                Irp = CONTAINING_RECORD(Packet, IRP, Tail.Overlay.ListEntry);
+                IoFreeIrp(Irp);
+            }
+            else
+            {
+                /* Use common routine */
+                IopFreeIoCompletionPacket(Packet);
+            }
+        } while (FirstEntry != CurrentEntry);
+    }
 }
 
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
+IoSetIoCompletion(IN PVOID IoCompletion,
+                  IN PVOID KeyContext,
+                  IN PVOID ApcContext,
+                  IN NTSTATUS IoStatus,
+                  IN ULONG_PTR IoStatusInformation,
+                  IN BOOLEAN Quota)
+{
+    PKQUEUE Queue = (PKQUEUE)IoCompletion;
+    PNPAGED_LOOKASIDE_LIST List;
+    PKPRCB Prcb = KeGetCurrentPrcb();
+    PIO_COMPLETION_PACKET Packet;
+
+    /* Get the P List */
+    List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].P;
+    
+    /* Try to allocate the Packet */
+    List->L.TotalAllocates++;
+    Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
+    
+    /* Check if that failed, use the L list if it did */
+    if (!Packet)
+    {
+        /* Let the balancer know */
+        List->L.AllocateMisses++;
+        
+        /* Get L List */
+        List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].L;
+    
+        /* Try to allocate the Packet */
+        List->L.TotalAllocates++;
+        Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
+    }
+    
+    /* Still failed, use pool */
+    if (!Packet)
+    {
+        /* Let the balancer know */
+        List->L.AllocateMisses++;
+        
+        /* Allocate from Nonpaged Pool */
+        Packet = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Packet), IOC_TAG);
+    }
+    
+    /* Make sure we have one by now... */
+    if (Packet)
+    {
+        /* Set up the Packet */
+        Packet->PacketType = IrpMiniCompletionPacket;
+        Packet->Key = KeyContext;
+        Packet->Context = ApcContext;
+        Packet->IoStatus.Status = IoStatus;
+        Packet->IoStatus.Information = IoStatusInformation;
+
+        /* Insert the Queue */
+        KeInsertQueue(Queue, &Packet->ListEntry);
+    }
+    else
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Return Success */
+    return STATUS_SUCCESS;
+}
 
-VOID 
-NtInitializeIoCompletionImplementation(VOID)
+/*
+ * @unimplemented
+ */
+NTSTATUS
+STDCALL
+IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject,
+                         IN PIRP Irp,
+                         IN PIO_COMPLETION_ROUTINE CompletionRoutine,
+                         IN PVOID Context,
+                         IN BOOLEAN InvokeOnSuccess,
+                         IN BOOLEAN InvokeOnError,
+                         IN BOOLEAN InvokeOnCancel)
 {
-   ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-   
-   RtlCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion");
-   
-   ExIoCompletionType->Tag = IOC_TAG;
-   ExIoCompletionType->MaxObjects = ULONG_MAX;
-   ExIoCompletionType->MaxHandles = ULONG_MAX;
-   ExIoCompletionType->TotalObjects = 0;
-   ExIoCompletionType->TotalHandles = 0;
-   ExIoCompletionType->PagedPoolCharge = 0;
-   ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE);
-   ExIoCompletionType->Mapping = &ExIoCompletionMapping;
-   ExIoCompletionType->Dump = NULL;
-   ExIoCompletionType->Open = NULL;
-   ExIoCompletionType->Close = NULL;
-   ExIoCompletionType->Delete = NtpDeleteIoCompletion;
-   ExIoCompletionType->Parse = NULL;
-   ExIoCompletionType->Security = NULL;
-   ExIoCompletionType->QueryName = NULL;
-   ExIoCompletionType->OkayToClose = NULL;
-   ExIoCompletionType->Create = NtpCreateIoCompletion;
-   ExIoCompletionType->DuplicationNotify = NULL;
-
-   ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
-                                   NULL,
-                                   NULL,
-                                   0,
-                                   sizeof(IO_COMPLETION_PACKET),
-                                   IOC_TAG,
-                                   0);
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
 }
 
+VOID
+FASTCALL
+IopInitIoCompletionImplementation(VOID)
+{
+    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+    UNICODE_STRING Name;
+
+    DPRINT("Creating IoCompletion Object Type\n");
+  
+    /* Initialize the Driver object type  */
+    RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+    RtlInitUnicodeString(&Name, L"IoCompletion");
+    ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+    ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KQUEUE);
+    ObjectTypeInitializer.PoolType = NonPagedPool;
+    ObjectTypeInitializer.ValidAccessMask = IO_COMPLETION_ALL_ACCESS;
+    ObjectTypeInitializer.UseDefaultObject = TRUE;
+    ObjectTypeInitializer.GenericMapping = IopCompletionMapping;
+    ObjectTypeInitializer.DeleteProcedure = IopDeleteIoCompletion;
+    ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoCompletionType);
+}
 
 NTSTATUS
 STDCALL
-NtCreateIoCompletion(
-   OUT PHANDLE             IoCompletionHandle,
-   IN  ACCESS_MASK         DesiredAccess,
-   IN  POBJECT_ATTRIBUTES  ObjectAttributes,
-   IN  ULONG               NumberOfConcurrentThreads
-   )
+NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle,
+                     IN  ACCESS_MASK DesiredAccess,
+                     IN  POBJECT_ATTRIBUTES ObjectAttributes,
+                     IN  ULONG NumberOfConcurrentThreads)
 {
-   PKQUEUE     Queue;
-   NTSTATUS    Status;
-   
-   Status = ObRosCreateObject(IoCompletionHandle,
-                           DesiredAccess,
-                           ObjectAttributes,
-                           ExIoCompletionType,
-                           (PVOID*)&Queue);
-
-   if (NT_SUCCESS(Status))
-   {
-      (void) KeInitializeQueue(Queue, NumberOfConcurrentThreads);
-      ObDereferenceObject(Queue);
-   }
+    PKQUEUE Queue;
+    HANDLE hIoCompletionHandle;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
 
-   return Status;
-   /*
+    PAGED_CODE();
+
+    if (PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteHandle(IoCompletionHandle);
+        } _SEH_HANDLE {
+
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
+
+        if (!NT_SUCCESS(Status)) {
 
-  CompletionPort = NULL OR ExistingCompletionPort
+            return Status;
+        }
+    }
 
-  */
+    /* Create the Object */
+    Status = ObCreateObject(PreviousMode,
+                            IoCompletionType,
+                            ObjectAttributes,
+                            PreviousMode,
+                            NULL,
+                            sizeof(KQUEUE),
+                            0,
+                            0,
+                            (PVOID*)&Queue);
 
+    /* Check for success */
+    if (NT_SUCCESS(Status)) {
+
+        /* Initialize the Queue */
+        KeInitializeQueue(Queue, NumberOfConcurrentThreads);
+
+        /* Insert it */
+        Status = ObInsertObject(Queue,
+                                NULL,
+                                DesiredAccess,
+                                0,
+                                NULL,
+                                &hIoCompletionHandle);
+        ObDereferenceObject(Queue);
+
+        if (NT_SUCCESS(Status)) {
+
+            _SEH_TRY {
+
+                *IoCompletionHandle = hIoCompletionHandle;
+            } _SEH_HANDLE {
+
+                Status = _SEH_GetExceptionCode();
+            } _SEH_END;
+        }
+   }
+
+   /* Return Status */
+   return Status;
 }
 
-/*
-DesiredAccess:
-ZERO
-IO_COMPLETION_QUERY_STATE Query access
-IO_COMPLETION_MODIFY_STATE Modify access
-IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL
-
-ObjectAttributes
-OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes
-
-Return Value
-STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or
-STATUS_OBJECT_NAME_NOT_FOUND.
-*/
 NTSTATUS
 STDCALL
-NtOpenIoCompletion(
-   OUT PHANDLE             IoCompletionHandle,
-   IN  ACCESS_MASK         DesiredAccess,
-   IN  POBJECT_ATTRIBUTES  ObjectAttributes
-   )
+NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle,
+                   IN ACCESS_MASK DesiredAccess,
+                   IN POBJECT_ATTRIBUTES ObjectAttributes)
 {
-   NTSTATUS Status;
-   
-   Status = ObOpenObjectByName(ObjectAttributes,
-                               ExIoCompletionType,
-                               NULL,
-                               UserMode,
-                               DesiredAccess,
-                               NULL,
-                               IoCompletionHandle);  //<- ???
-   
-   return Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    HANDLE hIoCompletionHandle;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+
+    if(PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteHandle(IoCompletionHandle);
+        } _SEH_HANDLE {
+
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
+
+        if(!NT_SUCCESS(Status)) {
+
+            return Status;
+        }
+    }
+
+    /* Open the Object */
+    Status = ObOpenObjectByName(ObjectAttributes,
+                                IoCompletionType,
+                                NULL,
+                                PreviousMode,
+                                DesiredAccess,
+                                NULL,
+                                &hIoCompletionHandle);
+
+    if (NT_SUCCESS(Status)) {
+
+        _SEH_TRY {
+
+            *IoCompletionHandle = hIoCompletionHandle;
+        } _SEH_HANDLE {
+
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
+    }
+
+    /* Return Status */
+    return Status;
 }
 
 
 NTSTATUS
 STDCALL
-NtQueryIoCompletion(
-   IN  HANDLE                          IoCompletionHandle,
-   IN  IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
-   OUT PVOID                           IoCompletionInformation,
-   IN  ULONG                           IoCompletionInformationLength,
-   OUT PULONG                          ResultLength OPTIONAL
-   )
+NtQueryIoCompletion(IN  HANDLE IoCompletionHandle,
+                    IN  IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
+                    OUT PVOID IoCompletionInformation,
+                    IN  ULONG IoCompletionInformationLength,
+                    OUT PULONG ResultLength OPTIONAL)
 {
-   PKQUEUE  Queue;
-   NTSTATUS Status;
-
-   if (IoCompletionInformationClass != IoCompletionBasicInformation)
-   {
-      return STATUS_INVALID_INFO_CLASS;
-   }
-   if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION))
-   {
-      return STATUS_INFO_LENGTH_MISMATCH;
-   }
-
-   Status = ObReferenceObjectByHandle( IoCompletionHandle,
+    PKQUEUE Queue;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+
+    /* Check buffers and parameters */
+    Status = DefaultQueryInfoBufferCheck(IoCompletionInformationClass,
+                                         IoCompletionInfoClass,
+                                         sizeof(IoCompletionInfoClass) / sizeof(IoCompletionInfoClass[0]),
+                                         IoCompletionInformation,
+                                         IoCompletionInformationLength,
+                                         ResultLength,
+                                         PreviousMode);
+    if(!NT_SUCCESS(Status)) {
+
+        DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status);
+        return Status;
+    }
+
+    /* Get the Object */
+    Status = ObReferenceObjectByHandle(IoCompletionHandle,
                                        IO_COMPLETION_QUERY_STATE,
-                                       ExIoCompletionType,
-                                       UserMode,
+                                       IoCompletionType,
+                                       PreviousMode,
                                        (PVOID*)&Queue,
                                        NULL);
-   if (NT_SUCCESS(Status))
-   {
-      ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = 
-         Queue->Header.SignalState;
 
-      ObDereferenceObject(Queue);
+    /* Check for Success */
+   if (NT_SUCCESS(Status)) {
 
-      if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
-   }
+        _SEH_TRY {
 
-   return Status;
-}
+            /* Return Info */
+            ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = KeReadStateQueue(Queue);
+            ObDereferenceObject(Queue);
+
+            /* Return Result Length if needed */
+            if (ResultLength) {
+
+                *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
+            }
+        } _SEH_HANDLE {
 
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
+    }
+
+    /* Return Status */
+    return Status;
+}
 
 /*
  * Dequeues an I/O completion message from an I/O completion object
  */
 NTSTATUS
 STDCALL
-NtRemoveIoCompletion(
-   IN  HANDLE           IoCompletionHandle,
-   OUT PULONG           CompletionKey,
-   OUT PULONG           CompletionValue,
-   OUT PIO_STATUS_BLOCK IoStatusBlock,
-   IN  PLARGE_INTEGER   Timeout OPTIONAL
-   )
+NtRemoveIoCompletion(IN  HANDLE IoCompletionHandle,
+                     OUT PVOID *CompletionKey,
+                     OUT PVOID *CompletionContext,
+                     OUT PIO_STATUS_BLOCK IoStatusBlock,
+                     IN  PLARGE_INTEGER Timeout OPTIONAL)
 {
-   PKQUEUE  Queue;
-   NTSTATUS Status;
-      
-   Status = ObReferenceObjectByHandle( IoCompletionHandle,
-                                       IO_COMPLETION_MODIFY_STATE,
-                                       ExIoCompletionType,
-                                       UserMode,
-                                       (PVOID*)&Queue,
-                                       NULL);
-   if (NT_SUCCESS(Status))
-   {
-      PIO_COMPLETION_PACKET   Packet;
-      PLIST_ENTRY             ListEntry;
+    LARGE_INTEGER SafeTimeout;
+    PKQUEUE Queue;
+    PIO_COMPLETION_PACKET Packet;
+    PLIST_ENTRY ListEntry;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
 
-      /*
-      Try 2 remove packet from queue. Wait (optionaly) if
-      no packet in queue or max num of threads allready running.
-      */
-      ListEntry = KeRemoveQueue(Queue, UserMode, Timeout );
+    PAGED_CODE();
 
-      ObDereferenceObject(Queue);
+    if (PreviousMode != KernelMode) {
 
-      Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
+        _SEH_TRY {
 
-      if (CompletionKey) *CompletionKey = Packet->Key;
-      if (CompletionValue) *CompletionValue = Packet->Overlapped;
-      if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
-
-      ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
-   }
+            ProbeForWritePointer(CompletionKey);
+            ProbeForWritePointer(CompletionContext);
+            ProbeForWrite(IoStatusBlock,
+                          sizeof(IO_STATUS_BLOCK),
+                          sizeof(ULONG));
+            if (Timeout != NULL) {
 
-   return Status;
-}
+                SafeTimeout = ProbeForReadLargeInteger(Timeout);
+                Timeout = &SafeTimeout;
+            }
+        } _SEH_HANDLE {
 
+            Status = _SEH_GetExceptionCode();
+        } _SEH_END;
 
-/*
-ASSOSIERT MED FOB's IoCompletionContext
+        if (!NT_SUCCESS(Status)) {
 
-typedef struct _IO_COMPLETION_CONTEXT {
-        PVOID Port; 
-        ULONG Key; 
-} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
+            return Status;
+        }
+    }
 
-*/
+    /* Open the Object */
+    Status = ObReferenceObjectByHandle(IoCompletionHandle,
+                                       IO_COMPLETION_MODIFY_STATE,
+                                       IoCompletionType,
+                                       PreviousMode,
+                                       (PVOID*)&Queue,
+                                       NULL);
 
+    /* Check for success */
+    if (NT_SUCCESS(Status)) {
+
+        /* Remove queue */
+        ListEntry = KeRemoveQueue(Queue, PreviousMode, Timeout);
+
+        /* If we got a timeout or user_apc back, return the status */
+        if ((NTSTATUS)ListEntry == STATUS_TIMEOUT || (NTSTATUS)ListEntry == STATUS_USER_APC) {
+
+            Status = (NTSTATUS)ListEntry;
+
+        } else {
+
+            /* Get the Packet Data */
+            Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
+
+            _SEH_TRY {
+
+                /* Check if this is piggybacked on an IRP */
+                if (Packet->PacketType == IrpCompletionPacket)
+                {
+                    /* Get the IRP */
+                    PIRP Irp = NULL;
+                    Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
+                    
+                    /* Return values to user */
+                    *CompletionKey = Irp->Tail.CompletionKey;
+                    *CompletionContext = Irp->Overlay.AsynchronousParameters.UserApcContext;
+                    *IoStatusBlock = Packet->IoStatus;
+                    IoFreeIrp(Irp);
+                }
+                else
+                {
+                    /* This is a user-mode generated or API generated mini-packet */
+                    *CompletionKey = Packet->Key;
+                    *CompletionContext = Packet->Context;
+                    *IoStatusBlock = Packet->IoStatus;
+                    IopFreeIoCompletionPacket(Packet);
+                }
+
+            } _SEH_HANDLE {
+
+                Status = _SEH_GetExceptionCode();
+            } _SEH_END;
+        }
+
+        /* Dereference the Object */
+        ObDereferenceObject(Queue);
+    }
+
+    /* Return status */
+    return Status;
+}
 
 /*
  * Queues an I/O completion message to an I/O completion object
  */
 NTSTATUS
 STDCALL
-NtSetIoCompletion(
-   IN HANDLE   IoCompletionPortHandle,
-   IN ULONG    CompletionKey,
-   IN ULONG    CompletionValue,
-   IN NTSTATUS CompletionStatus,
-   IN ULONG    CompletionInformation
-   )
+NtSetIoCompletion(IN HANDLE IoCompletionPortHandle,
+                  IN PVOID CompletionKey,
+                  IN PVOID CompletionContext,
+                  IN NTSTATUS CompletionStatus,
+                  IN ULONG CompletionInformation)
 {
-   NTSTATUS                Status;
-   PKQUEUE                 Queue;
+    NTSTATUS Status;
+    PKQUEUE Queue;
+
+    PAGED_CODE();
 
-   Status = ObReferenceObjectByHandle( IoCompletionPortHandle,
+    /* Get the Object */
+    Status = ObReferenceObjectByHandle(IoCompletionPortHandle,
                                        IO_COMPLETION_MODIFY_STATE,
-                                       ExIoCompletionType,
-                                       UserMode,
+                                       IoCompletionType,
+                                       ExGetPreviousMode(),
                                        (PVOID*)&Queue,
                                        NULL);
-   if (NT_SUCCESS(Status))
-   {
-      PIO_COMPLETION_PACKET   Packet;
-
-      Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
-
-      Packet->Key = CompletionKey;
-      Packet->Overlapped = CompletionValue;
-      Packet->IoStatus.Status = CompletionStatus;
-      Packet->IoStatus.Information = CompletionInformation;
-   
-      KeInsertQueue(Queue, &Packet->ListEntry);
-      ObDereferenceObject(Queue);
-   }
 
-   return Status;
+    /* Check for Success */
+    if (NT_SUCCESS(Status)) {
+
+        /* Set the Completion */
+        Status = IoSetIoCompletion(Queue,
+                                   CompletionKey,
+                                   CompletionContext,
+                                   CompletionStatus,
+                                   CompletionInformation,
+                                   TRUE);
+        ObDereferenceObject(Queue);
+    }
+
+    /* Return status */
+    return Status;
 }