mirror of
https://github.com/reactos/reactos.git
synced 2024-08-14 23:49:49 +00:00
307 lines
8.1 KiB
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 */
|