reactos/drivers/filesystems/npfs/waitsup.c

307 lines
8.1 KiB
C

/*
* 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 */