/* * PROJECT: ReactOS Named Pipe FileSystem * LICENSE: BSD - See COPYING.ARM in the top level directory * FILE: drivers/filesystems/npfs/waitsup.c * PURPOSE: Pipes Waiting Support * PROGRAMMERS: ReactOS Portable Systems Group */ /* INCLUDES *******************************************************************/ #include "npfs.h" // File ID number for NPFS bugchecking support #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_WAITSUP) /* FUNCTIONS ******************************************************************/ VOID NTAPI NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { KIRQL OldIrql; PNP_WAIT_QUEUE_ENTRY WaitEntry; PNP_WAIT_QUEUE WaitQueue; IoReleaseCancelSpinLock(Irp->CancelIrql); WaitQueue = Irp->Tail.Overlay.DriverContext[0]; KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql); WaitEntry = Irp->Tail.Overlay.DriverContext[1]; if (WaitEntry) { RemoveEntryList(&Irp->Tail.Overlay.ListEntry); if (!KeCancelTimer(&WaitEntry->Timer)) { WaitEntry->Irp = NULL; WaitEntry = NULL; } } KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql); if (WaitEntry) { ObDereferenceObject(WaitEntry->FileObject); ExFreePool(WaitEntry); } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT); } VOID NTAPI NpTimerDispatch(IN PKDPC Dpc, IN PVOID Context, IN PVOID Argument1, IN PVOID Argument2) { PIRP Irp; KIRQL OldIrql; PNP_WAIT_QUEUE_ENTRY WaitEntry = Context; KeAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock, &OldIrql); Irp = WaitEntry->Irp; if (Irp) { RemoveEntryList(&Irp->Tail.Overlay.ListEntry); if (!IoSetCancelRoutine(Irp, NULL)) { Irp->Tail.Overlay.DriverContext[1] = NULL; Irp = NULL; } } KeReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql); if (Irp) { Irp->IoStatus.Status = STATUS_IO_TIMEOUT; IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT); } ObDereferenceObject(WaitEntry->FileObject); ExFreePool(WaitEntry); } VOID NTAPI NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue) { InitializeListHead(&WaitQueue->WaitList); KeInitializeSpinLock(&WaitQueue->WaitLock); } static BOOLEAN NpEqualUnicodeString(IN PCUNICODE_STRING String1, IN PCUNICODE_STRING String2) { SIZE_T EqualLength; if (String1->Length != String2->Length) return FALSE; EqualLength = RtlCompareMemory(String1->Buffer, String2->Buffer, String1->Length); return EqualLength == String1->Length; } NTSTATUS NTAPI NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue, IN PUNICODE_STRING PipePath, IN NTSTATUS Status, IN PLIST_ENTRY List) { UNICODE_STRING PipePathUpper; KIRQL OldIrql; PWCHAR Buffer; PLIST_ENTRY NextEntry; PNP_WAIT_QUEUE_ENTRY WaitEntry, Linkage; PIRP WaitIrp; PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer; UNICODE_STRING WaitName, PipeName; Linkage = NULL; Buffer = ExAllocatePoolWithTag(NonPagedPool, PipePath->Length, NPFS_WAIT_BLOCK_TAG); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; RtlInitEmptyUnicodeString(&PipePathUpper, Buffer, PipePath->Length); RtlUpcaseUnicodeString(&PipePathUpper, PipePath, FALSE); KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql); NextEntry = WaitQueue->WaitList.Flink; while (NextEntry != &WaitQueue->WaitList) { WaitIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); NextEntry = NextEntry->Flink; WaitEntry = WaitIrp->Tail.Overlay.DriverContext[1]; if (WaitEntry->AliasName.Length) { ASSERT(FALSE); /* We have an alias. Use that for comparison */ WaitName = WaitEntry->AliasName; PipeName = PipePathUpper; } else { /* Use the name from the wait buffer to compare */ WaitBuffer = WaitIrp->AssociatedIrp.SystemBuffer; WaitName.Buffer = WaitBuffer->Name; WaitName.Length = WaitBuffer->NameLength; WaitName.MaximumLength = WaitName.Length; /* WaitName doesn't have a leading backslash, * so skip the one in PipePathUpper for the comparison */ PipeName.Buffer = PipePathUpper.Buffer + 1; PipeName.Length = PipePathUpper.Length - sizeof(WCHAR); PipeName.MaximumLength = PipeName.Length; } /* Can't use RtlEqualUnicodeString with a spinlock held */ if (NpEqualUnicodeString(&WaitName, &PipeName)) { /* Found a matching wait. Cancel it */ RemoveEntryList(&WaitIrp->Tail.Overlay.ListEntry); if (KeCancelTimer(&WaitEntry->Timer)) { WaitEntry->WaitQueue = (PNP_WAIT_QUEUE)Linkage; Linkage = WaitEntry; } else { WaitEntry->Irp = NULL; WaitIrp->Tail.Overlay.DriverContext[1] = NULL; } if (IoSetCancelRoutine(WaitIrp, NULL)) { WaitIrp->IoStatus.Information = 0; WaitIrp->IoStatus.Status = Status; InsertTailList(List, &WaitIrp->Tail.Overlay.ListEntry); } else { WaitIrp->Tail.Overlay.DriverContext[1] = NULL; } } } KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql); ExFreePoolWithTag(Buffer, NPFS_WAIT_BLOCK_TAG); while (Linkage) { WaitEntry = Linkage; Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue; ObDereferenceObject(WaitEntry->FileObject); ExFreePool(WaitEntry); } return STATUS_SUCCESS; } NTSTATUS NTAPI NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue, IN LARGE_INTEGER WaitTime, IN PIRP Irp, IN PUNICODE_STRING AliasName) { PIO_STACK_LOCATION IoStack; KIRQL OldIrql; NTSTATUS Status; PNP_WAIT_QUEUE_ENTRY WaitEntry; PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer; LARGE_INTEGER DueTime; ULONG i; IoStack = IoGetCurrentIrpStackLocation(Irp); WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, sizeof(*WaitEntry), NPFS_WRITE_BLOCK_TAG); if (!WaitEntry) { return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry); KeInitializeTimer(&WaitEntry->Timer); if (AliasName) { WaitEntry->AliasName = *AliasName; } else { WaitEntry->AliasName.Length = 0; WaitEntry->AliasName.Buffer = NULL; } WaitEntry->WaitQueue = WaitQueue; WaitEntry->Irp = Irp; WaitBuffer = Irp->AssociatedIrp.SystemBuffer; if (WaitBuffer->TimeoutSpecified) { DueTime = WaitBuffer->Timeout; } else { DueTime = WaitTime; } for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++) { WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]); } Irp->Tail.Overlay.DriverContext[0] = WaitQueue; Irp->Tail.Overlay.DriverContext[1] = WaitEntry; KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql); IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp); if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) { Status = STATUS_CANCELLED; } else { InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry); IoMarkIrpPending(Irp); Status = STATUS_PENDING; WaitEntry->FileObject = IoStack->FileObject; ObReferenceObject(WaitEntry->FileObject); KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc); WaitEntry = NULL; } KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql); if (WaitEntry) ExFreePool(WaitEntry); return Status; } /* EOF */