PLIST_ENTRY NTAPI NpGetNextRealDataQueueEntry(IN PNP_DATA_QUEUE DataQueue, IN PLIST_ENTRY List) { PNP_DATA_QUEUE_ENTRY DataEntry; ULONG Type; PIRP Irp; PLIST_ENTRY NextEntry; PAGED_CODE(); for (NextEntry = DataQueue->Queue.Flink; NextEntry != &DataQueue->Queue; NextEntry = DataQueue->Queue.Flink) { DataEntry = CONTAINING_RECORD(NextEntry, NP_DATA_QUEUE_ENTRY, QueueEntry); Type = DataEntry->DataEntryType; if (Type == Buffered || Type == Unbuffered) break; Irp = NpRemoveDataQueueEntry(DataQueue, FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } return NextEntry; }
NTSTATUS NTAPI NpSetDisconnectedPipeState(IN PNP_CCB Ccb, IN PLIST_ENTRY List) { PIRP Irp; PNP_NONPAGED_CCB NonPagedCcb; NTSTATUS Status; PLIST_ENTRY NextEntry; PNP_EVENT_BUFFER EventBuffer; NonPagedCcb = Ccb->NonPagedCcb; switch (Ccb->NamedPipeState) { case FILE_PIPE_DISCONNECTED_STATE: Status = STATUS_PIPE_DISCONNECTED; break; case FILE_PIPE_LISTENING_STATE: while (!IsListEmpty(&Ccb->IrpList)) { NextEntry = RemoveHeadList(&Ccb->IrpList); Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); if (IoSetCancelRoutine(Irp, NULL)) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, NextEntry); } else { InitializeListHead(NextEntry); } } Status = STATUS_SUCCESS; break; case FILE_PIPE_CONNECTED_STATE: EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END]; while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty) { Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } while (Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState != Empty) { Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_OUTBOUND], FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE); // drop down on purpose... queue will be empty so flush code is nop ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty); case FILE_PIPE_CLOSING_STATE: EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END]; while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty) { Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List); if (Irp) { Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED; InsertTailList(List, &Irp->Tail.Overlay.ListEntry); } } ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty); NpDeleteEventTableEntry(&NpVcb->EventTable, EventBuffer); NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END] = NULL; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; NpUninitializeSecurity(Ccb); if (Ccb->ClientSession) { ExFreePool(Ccb->ClientSession); Ccb->ClientSession = NULL; } Status = STATUS_SUCCESS; break; default: NpBugCheck(Ccb->NamedPipeState, 0, 0); break; } Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE; return Status; }
NTSTATUS NTAPI NpSetClosingPipeState(IN PNP_CCB Ccb, IN PIRP Irp, IN ULONG NamedPipeEnd, IN PLIST_ENTRY List) { PNP_NONPAGED_CCB NonPagedCcb; PNP_FCB Fcb; PLIST_ENTRY NextEntry; PNP_DATA_QUEUE ReadQueue, WriteQueue, DataQueue; PNP_EVENT_BUFFER EventBuffer; PIRP ListIrp; NonPagedCcb = Ccb->NonPagedCcb; Fcb = Ccb->Fcb; switch (Ccb->NamedPipeState) { case FILE_PIPE_LISTENING_STATE: ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END); while (!IsListEmpty(&Ccb->IrpList)) { NextEntry = RemoveHeadList(&Ccb->IrpList); ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); if (IoSetCancelRoutine(ListIrp, NULL)) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, NextEntry); } else { InitializeListHead(NextEntry); } } // Drop on purpose case FILE_PIPE_DISCONNECTED_STATE: ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END); NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; NpDeleteCcb(Ccb, List); if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List); break; case FILE_PIPE_CLOSING_STATE: if (NamedPipeEnd == FILE_PIPE_SERVER_END) { DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; } else { DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; } NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; while (DataQueue->QueueState != Empty) { ListIrp = NpRemoveDataQueueEntry(DataQueue, FALSE, List); if (ListIrp) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); } } NpUninitializeSecurity(Ccb); if (Ccb->ClientSession) { ExFreePool(Ccb->ClientSession); Ccb->ClientSession = NULL; } NpDeleteCcb(Ccb, List); if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List); break; case FILE_PIPE_CONNECTED_STATE: if (NamedPipeEnd == FILE_PIPE_SERVER_END) { ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE); Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL; } else { ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND]; WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND]; NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE); Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL; } EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd]; Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE; while (ReadQueue->QueueState != Empty) { ListIrp = NpRemoveDataQueueEntry(ReadQueue, FALSE, List); if (ListIrp) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); } } while (WriteQueue->QueueState == ReadEntries) { ListIrp = NpRemoveDataQueueEntry(WriteQueue, FALSE, List); if (ListIrp) { ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN; InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry); } } if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE); break; default: NpBugCheck(Ccb->NamedPipeState, 0, 0); break; } return STATUS_SUCCESS; }
NTSTATUS NTAPI NpWriteDataQueue(IN PNP_DATA_QUEUE WriteQueue, IN ULONG Mode, IN PVOID OutBuffer, IN ULONG OutBufferSize, IN ULONG PipeType, OUT PULONG BytesNotWritten, IN PNP_CCB Ccb, IN ULONG NamedPipeEnd, IN PETHREAD Thread, IN PLIST_ENTRY List) { BOOLEAN HaveContext = FALSE, MoreProcessing, AllocatedBuffer; PNP_DATA_QUEUE_ENTRY DataEntry; ULONG DataSize, BufferSize; PIRP WriteIrp; PIO_STACK_LOCATION IoStack; PVOID Buffer; NTSTATUS Status; PSECURITY_CLIENT_CONTEXT ClientContext; PAGED_CODE(); *BytesNotWritten = OutBufferSize; MoreProcessing = TRUE; if ((PipeType != FILE_PIPE_MESSAGE_MODE) || (OutBufferSize)) { MoreProcessing = FALSE; } for (DataEntry = CONTAINING_RECORD(NpGetNextRealDataQueueEntry(WriteQueue, List), NP_DATA_QUEUE_ENTRY, QueueEntry); ((WriteQueue->QueueState == ReadEntries) && ((*BytesNotWritten > 0) || (MoreProcessing))); DataEntry = CONTAINING_RECORD(NpGetNextRealDataQueueEntry(WriteQueue, List), NP_DATA_QUEUE_ENTRY, QueueEntry)) { DataSize = DataEntry->DataSize; IoStack = IoGetCurrentIrpStackLocation(DataEntry->Irp); if (IoStack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && IoStack->Parameters.FileSystemControl.FsControlCode == FSCTL_PIPE_INTERNAL_READ_OVFLOW && (DataSize < OutBufferSize || MoreProcessing)) { WriteIrp = NpRemoveDataQueueEntry(WriteQueue, TRUE, List); if (WriteIrp) { WriteIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; InsertTailList(List, &WriteIrp->Tail.Overlay.ListEntry); } continue; } if (DataEntry->DataEntryType == Unbuffered) { DataEntry->Irp->Overlay.AllocationSize.QuadPart = 0; } BufferSize = *BytesNotWritten; if (BufferSize >= DataSize) BufferSize = DataSize; if (DataEntry->DataEntryType != Unbuffered && BufferSize) { Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, NPFS_DATA_ENTRY_TAG); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; AllocatedBuffer = TRUE; } else { Buffer = DataEntry->Irp->AssociatedIrp.SystemBuffer; AllocatedBuffer = FALSE; } _SEH2_TRY { RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)OutBuffer + OutBufferSize - *BytesNotWritten), BufferSize); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { if (AllocatedBuffer) ExFreePool(Buffer); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; if (!HaveContext) { HaveContext = TRUE; Status = NpGetClientSecurityContext(NamedPipeEnd, Ccb, Thread, &ClientContext); if (!NT_SUCCESS(Status)) { if (AllocatedBuffer) ExFreePool(Buffer); return Status; } if (ClientContext) { NpFreeClientSecurityContext(Ccb->ClientContext); Ccb->ClientContext = ClientContext; } } WriteIrp = NpRemoveDataQueueEntry(WriteQueue, TRUE, List); if (WriteIrp) { *BytesNotWritten -= BufferSize; WriteIrp->IoStatus.Information = BufferSize; if (AllocatedBuffer) { WriteIrp->AssociatedIrp.SystemBuffer = Buffer; WriteIrp->Flags |= IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO | IRP_INPUT_OPERATION; } if (!*BytesNotWritten) { MoreProcessing = FALSE; WriteIrp->IoStatus.Status = STATUS_SUCCESS; InsertTailList(List, &WriteIrp->Tail.Overlay.ListEntry); continue; } if (Mode == FILE_PIPE_MESSAGE_MODE) { WriteIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; } else { WriteIrp->IoStatus.Status = STATUS_SUCCESS; } InsertTailList(List, &WriteIrp->Tail.Overlay.ListEntry); } else if (AllocatedBuffer) { ExFreePool(Buffer); } } if (*BytesNotWritten > 0 || MoreProcessing) { ASSERT(WriteQueue->QueueState != ReadEntries); Status = STATUS_MORE_PROCESSING_REQUIRED; } else { Status = STATUS_SUCCESS; } return Status; }