From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/npfs/datasup.c | 1077 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1077 insertions(+) create mode 100644 private/ntos/npfs/datasup.c (limited to 'private/ntos/npfs/datasup.c') diff --git a/private/ntos/npfs/datasup.c b/private/ntos/npfs/datasup.c new file mode 100644 index 000000000..1adbace32 --- /dev/null +++ b/private/ntos/npfs/datasup.c @@ -0,0 +1,1077 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + DataSup.c + +Abstract: + + This module implements the Named Pipe data queue support routines. + +Author: + + Gary Kimura [GaryKi] 30-Aug-1990 + +Revision History: + +--*/ + +#include "NpProcs.h" + +// +// The debug trace level +// + +#define Dbg (DEBUG_TRACE_DATASUP) + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NpGetNextRealDataQueueEntry) +#pragma alloc_text(PAGE, NpInitializeDataQueue) +#pragma alloc_text(PAGE, NpUninitializeDataQueue) +#endif + +// +// The following macro is used to dump a data queue +// + +#define DumpDataQueue(S,P) { \ + ULONG NpDumpDataQueue(IN PDATA_QUEUE Ptr); \ + DebugTrace(0,Dbg,S,0); \ + DebugTrace(0,Dbg,"", NpDumpDataQueue(P)); \ +} + +// +// This is a debugging aid +// + +_inline BOOLEAN +NpfsVerifyDataQueue( IN ULONG Line, IN PDATA_QUEUE DataQueue ) { + PDATA_ENTRY Entry; + ULONG BytesInQueue = 0; + ULONG EntriesInQueue = 0; + for (Entry = DataQueue->FrontOfQueue; Entry != NULL; Entry = Entry->Next) { + BytesInQueue += Entry->DataSize; + EntriesInQueue += 1; + if (Entry->Next == NULL) { + if (Entry != DataQueue->EndOfQueue) { + DbgPrint("%d DataQueue does not end corretly %08lx\n", Line, DataQueue ); + DbgBreakPoint(); + } + } + } + if ((DataQueue->EntriesInQueue != EntriesInQueue) || + (DataQueue->BytesInQueue != BytesInQueue)) { + DbgPrint("%d DataQueue is illformed %08lx %x %x\n", Line, DataQueue, BytesInQueue, EntriesInQueue); + DbgBreakPoint(); + return FALSE; + } + return TRUE; +} + + +VOID +NpCancelDataQueueIrp ( + IN PDEVICE_OBJECT DevictObject, + IN PIRP Irp + ); + + +VOID +NpInitializeDataQueue ( + IN PDATA_QUEUE DataQueue, + IN PEPROCESS Process, + IN ULONG Quota + ) + +/*++ + +Routine Description: + + This routine initializes a new data queue. The indicated quota is taken + from the process and not returned until the data queue is uninitialized. + +Arguments: + + DataQueue - Supplies the data queue being initialized + + Process - Supplies a pointer to the process creating the named pipe + + Quota - Supplies the quota to assign to the data queue + +Return Value: + + None. + +--*/ + +{ + PAGED_CODE(); + + DebugTrace(+1, Dbg, "NpInitializeDataQueue, DataQueue = %08lx\n", DataQueue); + + // + // First thing we do is get the process's quota, if we can't get it + // then this call will raise status + // + + ObReferenceObject( Process ); + PsChargePoolQuota( Process, NonPagedPool, Quota ); + + // + // Now we can initialize the data queue structure + // + + DataQueue->QueueState = Empty; + DataQueue->BytesInQueue = 0; + DataQueue->EntriesInQueue = 0; + DataQueue->Quota = Quota; + DataQueue->QuotaUsed = 0; + DataQueue->FrontOfQueue = NULL; + DataQueue->EndOfQueue = NULL; + DataQueue->NextByteOffset = 0; + + // + // And return to our caller + // + + DebugTrace(-1, Dbg, "NpInitializeDataQueue -> VOID\n", 0); + + return; +} + + +VOID +NpUninitializeDataQueue ( + IN PDATA_QUEUE DataQueue, + IN PEPROCESS Process + ) + +/*++ + +Routine Description: + + This routine uninitializes a data queue. The previously debited quota + is returned to the process. + +Arguments: + + DataQueue - Supplies the data queue being uninitialized + + Process - Supplies a pointer to the process who created the named pipe + +Return Value: + + None. + +--*/ + +{ + PAGED_CODE(); + + DebugTrace(+1, Dbg, "NpUninitializeDataQueue, DataQueue = %08lx\n", DataQueue); + + // + // Assert that the queue is empty + // + + ASSERT( DataQueue->QueueState == Empty ); + + // + // Return all of our quota back to the process + // + + PsReturnPoolQuota( Process, NonPagedPool, DataQueue->Quota ); + ObDereferenceObject( Process ); + + // + // Then for safety sake we'll zero out the data queue structure + // + + RtlZeroMemory( DataQueue, sizeof(DATA_QUEUE ) ); + + // + // And return to our caller + // + + DebugTrace(-1, Dbg, "NpUnininializeDataQueue -> VOID\n", 0); + + return; +} + + +PDATA_ENTRY +NpAddDataQueueEntry ( + IN PDATA_QUEUE DataQueue, + IN QUEUE_STATE Who, + IN DATA_ENTRY_TYPE Type, + IN ULONG DataSize, + IN PIRP Irp OPTIONAL, + IN PVOID DataPointer OPTIONAL + ) + +/*++ + +Routine Description: + + This routine adds a new data entry to the end of the data queue. + If necessary it will allocate a data entry buffer, or use space in + the IRP, and possibly complete the indicated IRP. + + The different actions we are perform are based on the type and who + parameters and quota requirements. + + Type == Internal (i.e, Unbuffered) + + +------+ - Allocate Data Entry from Irp + |Irp | +----------+ + | |<---|Unbuffered| - Reference Irp + +------+ |InIrp | + | +----------+ - Use system buffer from Irp + v | + +------+ | + |System|<-----+ + |Buffer| + +------+ + + Type == Buffered && Who == ReadEntries + + +----------+ - Allocate Data Entry from Irp + |Irp | +-----------+ + |BufferedIo|<----|Buffered | - Allocate New System buffer + |DeallBu...| |EitherQuota| + +----------+ +-----------+ - Reference and modify Irp to + | | | do Buffered I/O, Deallocate + v | v buffer, and have io completion + +------+ +------>+------+ copy the buffer (Input operation) + |User | |System| + |Buffer| |Buffer| + +------+ +------+ + + Type == Buffered && Who == WriteEntries && PipeQuota Available + + +----------+ - Allocate Data Entry from Quota + |Irp | +-----------+ + | | |Buffered | - Allocate New System buffer + | | |PipeQuota | + +----------+ +-----------+ - Copy data from User buffer to + | | system buffer + v v + +------+ +------+ - Complete Irp + |User |..copy..>|System| + |Buffer| |Buffer| + +------+ +------+ + + Type == Buffered && Who == WriteEntries && PipeQuota Not Available + + +----------+ - Allocate Data Entry from Irp + |Irp | +-----------+ + |BufferedIo|<----|Buffered | - Allocate New System buffer + |DeallBuff | |UserQuota | + +----------+ +-----------+ - Reference and modify Irp to use + | | | the new system buffer, do Buffered + v | v I/O, and Deallocate buffer + +------+ +------>+------+ + |User | |System| - Copy data from User buffer to + |Buffer|..copy..>|Buffer| system buffer + +------+ +------+ + + Type == Flush or Close + + +----------+ - Allocate Data Entry from Irp + |Irp | +-----------+ + | |<----|Buffered | - Reference the Irp + | | |UserQuota | + +----------+ +-----------+ + +Arguments: + + DataQueue - Supplies the Data queue being modified + + Who - Indicates if this is the reader or writer that is adding to the pipe + + Type - Indicates the type of entry to add to the data queue + + DataSize - Indicates the size of the data buffer needed to represent + this entry + + Irp - Supplies a pointer to the Irp responsible for this entry + The irp is only optional for buffered write with available pipe quota + + DataPointer - If the Irp is not supplied then this field points to the + user's write buffer. + +Return Value: + + PDATA_ENTRY - Returns a pointer to the newly added data entry + +--*/ + +{ + PDATA_ENTRY DataEntry; + PIRP IrpToComplete; + + // + // The following array indicates storage that needs to be deallocated + // on an abnormal unwind. + // + + PVOID Unwind[2] = { NULL, NULL }; + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + + DebugTrace(+1, Dbg, "NpAddDataQueueEntry, DataQueue = %08lx\n", DataQueue); + + IrpToComplete = NULL; + + try { + + // + // Case on the type of operation we are doing + // + + switch (Type) { + + case Unbuffered: + + ASSERT(ARGUMENT_PRESENT(Irp)); + + // + // Allocate a data entry from the Irp + // + + DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp ); + + DataEntry->DataEntryType = Unbuffered; + DataEntry->From = InIrp; + DataEntry->Irp = Irp; + DataEntry->DataSize = DataSize; + DataEntry->DataPointer = Irp->AssociatedIrp.SystemBuffer; + + DataEntry->SecurityClientContext = NULL; + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + + break; + + case Buffered: + + // + // Check if this is the reader or writer + // + + if (Who == ReadEntries) { + + ASSERT(ARGUMENT_PRESENT(Irp)); + + // + // Allocate a data entry from the Irp, and allocate a new + // system buffer + // + + DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp ); + + DataEntry->DataEntryType = Buffered; + DataEntry->Irp = Irp; + DataEntry->DataSize = DataSize; + + if ((DataQueue->Quota - DataQueue->QuotaUsed) >= DataSize) { + + DataEntry->DataPointer = Unwind[0] = (DataSize != 0 ? FsRtlAllocatePool( NonPagedPool, DataSize ) : NULL); + + DataQueue->QuotaUsed += DataSize; + + DataEntry->From = PipeQuota; + + } else { + + DataEntry->DataPointer = Unwind[1] = (DataSize != 0 ? FsRtlAllocatePoolWithQuota( NonPagedPool, DataSize ) : NULL); + + DataEntry->From = UserQuota; + } + + DataEntry->SecurityClientContext = NULL; + + // + // Modify the Irp to be buffered I/O, deallocate the buffer, copy + // the buffer on completion, and to reference the new system + // buffer + // + + if (DataSize != 0) { + + Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION; + Irp->AssociatedIrp.SystemBuffer = DataEntry->DataPointer; + } + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + + } else { + + // + // This is a writer entry + // + + // + // If there is enough quota left in the pipe then we will + // allocate the data entry and data buffer from the pipe quota + // + + if ((DataQueue->Quota - DataQueue->QuotaUsed) >= sizeof(DATA_ENTRY) + DataSize) { + + DataEntry = Unwind[0] = FsRtlAllocatePool( NonPagedPool, sizeof(DATA_ENTRY) ); + + DataEntry->DataPointer = Unwind[1] = (DataSize != 0 ? FsRtlAllocatePool( NonPagedPool, DataSize ) : NULL); + + DataQueue->QuotaUsed += sizeof(DATA_ENTRY) + DataSize; + + DataEntry->DataEntryType = Buffered; + DataEntry->From = PipeQuota; + DataEntry->Irp = NULL; + DataEntry->DataSize = DataSize; + + DataEntry->SecurityClientContext = NULL; + + // + // Safely copy the user buffer to the new system buffer using either + // the irp user buffer is supplied of the data pointer we were given + // + + if (ARGUMENT_PRESENT(Irp)) { DataPointer = Irp->UserBuffer; } + + try { + + RtlCopyMemory( DataEntry->DataPointer, DataPointer, DataSize ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ExRaiseStatus( STATUS_INVALID_USER_BUFFER ); + } + + IrpToComplete = Irp; + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + + } else { + + ASSERT(ARGUMENT_PRESENT(Irp)); + + // + // There isn't enough pipe quota to do this so we will + // use the user quota + // + // Allocate a data entry from the Irp, and allocate a new + // system buffer + // + + DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp ); + + DataEntry->DataEntryType = Buffered; + DataEntry->From = UserQuota; + DataEntry->Irp = Irp; + DataEntry->DataSize = DataSize; + + DataEntry->SecurityClientContext = NULL; + + DataEntry->DataPointer = Unwind[0] = (DataSize != 0 ? FsRtlAllocatePoolWithQuota( NonPagedPool, DataSize ) : NULL); + + // + // Safely copy the user buffer to the new system buffer + // + + try { + + RtlCopyMemory( DataEntry->DataPointer, Irp->UserBuffer, DataSize ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ExRaiseStatus( STATUS_INVALID_USER_BUFFER ); + } + + // + // Modify the Irp to be buffered I/O, deallocate the buffer + // and to reference the new system buffer + // + + if (DataSize != 0) { + + Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; + Irp->AssociatedIrp.SystemBuffer = DataEntry->DataPointer; + } + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + } + } + + break; + + case Flush: + case Close: + + ASSERT(ARGUMENT_PRESENT(Irp)); + + // + // Allocate a data entry from the Irp + // + + DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp ); + + DataEntry->DataEntryType = Type; + DataEntry->From = InIrp; + DataEntry->Irp = Irp; + DataEntry->DataSize = 0; + DataEntry->DataPointer = NULL; + + DataEntry->SecurityClientContext = NULL; + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + + break; + } + + ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); + + // + // Now data entry points to a new data entry to add to the data queue + // Check if the queue is empty otherwise we will add this entry to + // the end of the queue + // + + DataEntry->Next = NULL; + + if (DataQueue->QueueState == Empty) { + + DataQueue->QueueState = Who; + DataQueue->BytesInQueue = DataEntry->DataSize; + DataQueue->EntriesInQueue = 1; + DataQueue->FrontOfQueue = DataEntry; + DataQueue->EndOfQueue = DataEntry; + + } else { + + ASSERT( DataQueue->QueueState == Who ); + + DataQueue->BytesInQueue += DataEntry->DataSize; + DataQueue->EntriesInQueue += 1; + DataQueue->EndOfQueue->Next = DataEntry; + + DataQueue->EndOfQueue = DataEntry; + } + + } finally { + + // + // If this is an abnormal termination then deallocate any storage + // that we may have allocated + // + + if (AbnormalTermination()) { + + if (Unwind[0] != NULL) { ExFreePool( Unwind[0] ); } + if (Unwind[1] != NULL) { ExFreePool( Unwind[1] ); } + + } else { + + if (IrpToComplete != NULL) { + + NpCompleteRequest( IrpToComplete, STATUS_SUCCESS ); + + } else if (ARGUMENT_PRESENT(Irp)) { + + IoAcquireCancelSpinLock( &Irp->CancelIrql ); + Irp->IoStatus.Status = (ULONG)DataQueue; + + if (Irp->Cancel) { + + // + // Indicate in the first parameter that we're calling the + // cancel routine and not the I/O system. Therefore + // the routine won't take out the VCB exclusive. + // + + NpCancelDataQueueIrp( ((PVOID)0x1), Irp ); + + } else { + + IoSetCancelRoutine( Irp, NpCancelDataQueueIrp ); + IoReleaseCancelSpinLock( Irp->CancelIrql ); + } + } + } + + DumpDataQueue( "After AddDataQueueEntry\n", DataQueue ); + DebugTrace(-1, Dbg, "NpAddDataQueueEntry -> %08lx\n", DataEntry); + } + + // + // And return to our caller + // + + return DataEntry; +} + + +PIRP +NpRemoveDataQueueEntry ( + IN PDATA_QUEUE DataQueue + ) + +/*++ + +Routine Description: + + This routines remove the first entry from the front of the indicated + data queue, and possibly returns the Irp associated with the entry if + it wasn't already completed when we did the insert. + + If the data entry we are removing indicates buffered I/O then we also + need to deallocate the data buffer besides the data entry but only + if the Irp is null. Note that the data entry might be stored in an IRP. + If it is then we are going to return the IRP it is stored in. + +Arguments: + + DataQueue - Supplies a pointer to the data queue being modifed + +Return Value: + + PIRP - Possibly returns a pointer to an IRP. + +--*/ + +{ + PDATA_ENTRY DataEntry; + + DATA_ENTRY_TYPE DataEntryType; + FROM From; + PIRP Irp; + ULONG DataSize; + PVOID DataPointer; + PSECURITY_CLIENT_CONTEXT ClientContext; + + DebugTrace(+1, Dbg, "NpRemoveDataQueueEntry, DataQueue = %08lx\n", DataQueue); + + // + // Check if the queue is empty, and if so then we simply return null + // + + if (DataQueue->QueueState == Empty) { + + Irp = NULL; + + } else { + + // + // Reference the front of the data queue, and remove the entry + // from the queue itself. + // + + DataEntry = DataQueue->FrontOfQueue; + DataQueue->FrontOfQueue = DataEntry->Next; + DataQueue->BytesInQueue -= DataEntry->DataSize; + DataQueue->EntriesInQueue -= 1; + + // + // Now if the queue is empty we need to reset the end of queue and + // queue state + // + + if (DataQueue->FrontOfQueue == NULL) { + + DataQueue->EndOfQueue = NULL; + DataQueue->QueueState = Empty; + } + + // + // Capture some of the fields from the data entry to make our + // other references a little easier + // + + DataEntryType = DataEntry->DataEntryType; + From = DataEntry->From; + Irp = DataEntry->Irp; + DataSize = DataEntry->DataSize; + DataPointer = DataEntry->DataPointer; + ClientContext = DataEntry->SecurityClientContext; + + // + // Check if we should delete the client context + // + + if (ClientContext != NULL) { + + SeDeleteClientSecurity( ClientContext ); + ExFreePool( ClientContext ); + } + + // + // Check if we need to deallocate the data buffer, we only need + // to deallocate it if it is buffered and the Irp is null + // + + if (DataEntryType == Buffered) { + + if ((Irp == NULL) && (DataPointer != NULL)) { + + ExFreePool( DataPointer ); + } + + // + // Now the preceding call returned the user's quota or it + // simply deallocated the buffer. If it only deallocated + // the buffer then we need to credit our quota + // + + if (From == PipeQuota) { + + DataQueue->QuotaUsed -= DataSize; + } + } + + // + // Now check if we still have an IRP to return. If we do then + // we know that this data entry is located in the current IRP + // stack location and we need to zero out the data entry (skipping + // over the spare field), otherwise we got allocated from either + // the pipe or user quota, and we need to deallocate it ourselves. + // + // Note that we'll keep the data entry type field intact so that + // out caller will know if this is an internal read operation. + // + + if (Irp != NULL) { + + DataEntry->From = 0; + DataEntry->Next = 0; + DataEntry->Irp = 0; + DataEntry->DataSize = 0; + DataEntry->DataPointer = 0; + + DataEntry->SecurityClientContext = NULL; + + IoAcquireCancelSpinLock( &Irp->CancelIrql ); + IoSetCancelRoutine( Irp, NULL ); + IoReleaseCancelSpinLock( Irp->CancelIrql ); + + } else { + + if (DataPointer != NULL) { + + ExFreePool( DataEntry ); + } + + // + // Now the preceding call returned the user's quota or it + // simply deallocated the buffer. If it only deallocated + // the buffer then we need to credit our quota + // + + if (From == PipeQuota) { + + DataQueue->QuotaUsed -= sizeof(DATA_ENTRY); + } + } + } + + // + // In all cases we'll also zero out the next byte offset. + // + + DataQueue->NextByteOffset = 0; + + // + // And return to our caller + // + + DumpDataQueue( "After RemoveDataQueueEntry\n", DataQueue ); + DebugTrace(-1, Dbg, "NpRemoveDataQueueEntry -> %08lx\n", Irp); + + return Irp; +} + + +PDATA_ENTRY +NpGetNextRealDataQueueEntry ( + IN PDATA_QUEUE DataQueue + ) + +/*++ + +Routine Description: + + This routine will returns a pointer to the next real data queue entry + in the indicated data queue. A real entry is either a read or write + entry (i.e., buffered or unbuffered). It will complete (as necessary) + any flush and close Irps that are in the queue until either the queue + is empty or a real data queue entry is at the front of the queue. + +Arguments: + + DataQueue - Supplies a pointer to the data queue being modified + +Return Value: + + PDATA_ENTRY - Returns a pointer to the next data queue entry or NULL + if there isn't any. + +--*/ + +{ + PDATA_ENTRY DataEntry; + PIRP Irp; + + PAGED_CODE(); + + DebugTrace(+1, Dbg, "NpGetNextRealDataQueueEntry, DataQueue = %08lx\n", DataQueue); + + // + // While the next data queue entry at the head of the data queue is not + // a real data queue entry we'll dequeue that entry and complete + // its corresponding IRP. + // + + for (DataEntry = NpGetNextDataQueueEntry( DataQueue, NULL); + + (DataEntry != NULL) && + ((DataEntry->DataEntryType != Buffered) && + (DataEntry->DataEntryType != Unbuffered)); + + DataEntry = NpGetNextDataQueueEntry( DataQueue, NULL)) { + + // + // We have a non real data queue entry that needs to be removed + // and completed. + // + + Irp = NpRemoveDataQueueEntry( DataQueue ); + + if (Irp != NULL) { + + NpCompleteRequest( Irp, STATUS_SUCCESS ); + } + } + + // + // At this point we either have an empty data queue and data entry is + // null, or we have a real data queue entry. In either case it + // is time to return to our caller + // + + DebugTrace(-1, Dbg, "NpGetNextRealDataQueueEntry -> %08lx\n", DataEntry); + + return DataEntry; +} + + +// +// Local support routine +// + +VOID +NpCancelDataQueueIrp ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This routine implements the cancel function for an IRP saved in a + data queue + +Arguments: + + DeviceObject - Generally ignored but the low order bit is a flag indicating + if we are being called locally (i.e., not from the I/O system) and + therefore don't need to take out the VCB. + + Irp - Supplies the Irp being cancelled. A pointer to the data queue + structure is stored in the information field of the Irp Iosb + field. + +Return Value: + + None. + +--*/ + +{ + PDATA_QUEUE DataQueue; + + PDATA_ENTRY DataEntry; + PDATA_ENTRY *Previous; + + // + // The status field is used to store a pointer to the data queue + // containing this irp + // + + DataQueue = (PDATA_QUEUE)Irp->IoStatus.Status; + + // + // We now need to void the cancel routine and release the io cancel spinlock + // + + IoSetCancelRoutine( Irp, NULL ); + IoReleaseCancelSpinLock( Irp->CancelIrql ); + + // + // Get exclusive access to the named pipe vcb so we can now do our work + // but only if we need to + // + + if (DeviceObject != (PVOID)0x1) { NpAcquireExclusiveVcb(); } + + try { + + // + // Scan through the data queue looking for entries that have Irps + // that have been cancelled. We use previous to point to the pointer to + // the data entry we're examining. We cannot do this in a for loop + // because we'll have a tough time setting up ourselves for another iteration + // when we remove an entry + // + + Previous = &DataQueue->FrontOfQueue; + DataEntry = *Previous; + + while (DataEntry != NULL) { + + // + // If the data entry contains an Irp and the irp is cancelled then + // we have some work do to + // + + if ((DataEntry->Irp != NULL) && (DataEntry->Irp->Cancel)) { + + DATA_ENTRY_TYPE DataEntryType; + FROM From; + PIRP Irp; + ULONG DataSize; + PVOID DataPointer; + PSECURITY_CLIENT_CONTEXT ClientContext; + + // + // First remove this data entry from the queue + // Later we will fixup Data entry to the next entry + // + + *Previous = DataEntry->Next; + + // + // If the queue is now empty then we need to fix the queue + // state and end of queue pointer + // + + if (DataQueue->FrontOfQueue == NULL) { + + DataQueue->EndOfQueue = NULL; + DataQueue->QueueState = Empty; + + // + // If we removed the last entry in the list then we need to update + // the end of the queue + // + + } else if (DataEntry == DataQueue->EndOfQueue) { + + DataQueue->EndOfQueue = (PDATA_ENTRY)Previous; + } + + // + // Capture some of the fields from the data entry to make our + // other references a little easier + // + + DataEntryType = DataEntry->DataEntryType; + From = DataEntry->From; + Irp = DataEntry->Irp; + DataSize = DataEntry->DataSize; + DataPointer = DataEntry->DataPointer; + ClientContext = DataEntry->SecurityClientContext; + + // + // Check if we should delete the client context + // + + if (ClientContext != NULL) { + + SeDeleteClientSecurity( ClientContext ); + ExFreePool( ClientContext ); + } + + // + // Check if we need to return pipe quota for a buffered entry. + // + + if ((DataEntryType == Buffered) && (From == PipeQuota)) { + + DataQueue->QuotaUsed -= DataSize; + } + + // + // Update the data queue header information + // + + DataQueue->BytesInQueue -= DataSize; + DataQueue->EntriesInQueue -= 1; + + // + // Zero our the data entry + // + + DataEntry->From = 0; + DataEntry->Next = 0; + DataEntry->Irp = 0; + DataEntry->DataSize = 0; + DataEntry->DataPointer = 0; + + DataEntry->SecurityClientContext = NULL; + + // + // If what we removed is in the front of the queue then we must + // reset the next byte offset + // + + if (Previous == &DataQueue->FrontOfQueue) { + + DataQueue->NextByteOffset = 0; + } + + // + // Finally complete the request saying that it has been cancelled. + // + + NpCompleteRequest( Irp, STATUS_CANCELLED ); + + // + // And because the data entry is gone we now need to reset + // it so we can continue our while loop + // + + DataEntry = *Previous; + + } else { + + // + // Skip over to the next data entry + // + + Previous = &DataEntry->Next; + DataEntry = DataEntry->Next; + } + } + + } finally { + + if (DeviceObject != (PVOID)0x1) { NpReleaseVcb(); } + } + + // + // And return to our caller + // + + return; +} -- cgit v1.2.3