reactos/reactos/drivers/filesystems/npfs_new/statesup.c
Alex Ionescu 5492bdcde2 For our 60000th commit, I bring you a complete rewrite of the Named Pipe File System. It is not yet "active", but I consider this to now be largely code complete and worthy of the prize (and I didn't want to delay other commiters any further). Once the code is reviewed, fixed, tested, and commented, it will replace our old and aging NPFS. This driver is cross-compatible with Windows Server 2003. It is expected to fix winetest incompatiblities, speed up performance, and reduce bizare RPC/SCM issues. This commit is dedicated to my best friend Rachel, who has not only always been there for me, but was also the motivating factor behind my return to my passion -- ReactOS :)
[NPFS-NEW]: Implement QueryVolume, QuerySecurity, SetSecurity. Everything but Directory Query, Fast I/O, and a few rare FSCTLs is implemented now. The former two will come in an upcoming commit.
[NPFS-NEW]: Major cleanup in the way some member variables were being addressed. Reference them as array members based on the correct FILE_PIPE defines from now on. Also fix a lot of formatting issues. Fix a bunch of bugs that were found. Use FILE_PIPE_SERVER_END and FILE_PIPE_CLIENT_END intead of a BOOLEAN. Use TRUE/FALSE/STATUS_SUCCESS/NULL/etc when needed intead of 0/1. The code formatting can/should still be improved, but this was a big help.

svn path=/trunk/; revision=60000
2013-09-10 08:36:25 +00:00

371 lines
11 KiB
C

#include "npfs.h"
VOID
NTAPI
NpCancelListeningQueueIrp(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
FsRtlEnterFileSystem();
ExAcquireResourceExclusiveLite(&NpVcb->Lock, TRUE);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
FsRtlExitFileSystem();
ExReleaseResourceLite(&NpVcb->Lock);
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
}
NTSTATUS
NTAPI
NpSetConnectedPipeState(IN PNP_CCB Ccb,
IN PFILE_OBJECT FileObject,
IN PLIST_ENTRY List)
{
PLIST_ENTRY NextEntry;
PIRP Irp;
ASSERT(Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE);
Ccb->ReadMode[FILE_PIPE_CLIENT_END] = FILE_PIPE_BYTE_STREAM_MODE;
Ccb->CompletionMode[FILE_PIPE_CLIENT_END] = FILE_PIPE_QUEUE_OPERATION;
Ccb->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
Ccb->FileObject[FILE_PIPE_CLIENT_END] = FileObject;
NpSetFileObject(FileObject, Ccb, Ccb->NonPagedCcb, FALSE);
while (!IsListEmpty(&Ccb->IrpList))
{
NextEntry = RemoveHeadList(&Ccb->IrpList);
Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(Irp, NULL))
{
Irp->IoStatus.Status = STATUS_SUCCESS;
InsertTailList(List, NextEntry);
}
else
{
InitializeListHead(NextEntry);
}
}
return STATUS_SUCCESS;
}
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);
Status = STATUS_SUCCESS;
break;
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:
KeBugCheckEx(NPFS_FILE_SYSTEM, 0x1603DD, Ccb->NamedPipeState, 0, 0);
break;
}
Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
return Status;
}
NTSTATUS
NTAPI
NpSetListeningPipeState(IN PNP_CCB Ccb,
IN PIRP Irp,
IN PLIST_ENTRY List)
{
NTSTATUS Status;
switch (Ccb->NamedPipeState)
{
case FILE_PIPE_DISCONNECTED_STATE:
Status = NpCancelWaiter(&NpVcb->WaitQueue,
&Ccb->Fcb->FullName,
STATUS_SUCCESS,
List);
if (!NT_SUCCESS(Status)) return Status;
//
// Drop down on purpose
//
case FILE_PIPE_LISTENING_STATE:
if (Ccb->CompletionMode[FILE_PIPE_SERVER_END] == FILE_PIPE_COMPLETE_OPERATION)
{
Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
return STATUS_PIPE_LISTENING;
}
IoSetCancelRoutine(Irp, NpCancelListeningQueueIrp);
if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
{
return STATUS_CANCELLED;
}
Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
IoMarkIrpPending(Irp);
InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
return STATUS_PENDING;
case FILE_PIPE_CONNECTED_STATE:
Status = STATUS_PIPE_CONNECTED;
break;
case FILE_PIPE_CLOSING_STATE:
Status = STATUS_PIPE_CLOSING;
break;
default:
KeBugCheckEx(NPFS_FILE_SYSTEM, 0x160133, Ccb->NamedPipeState, 0, 0);
break;
}
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;
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);
Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(Irp, NULL))
{
Irp->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)
{
Irp = NpRemoveDataQueueEntry(DataQueue, FALSE, List);
if (Irp)
{
Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
InsertTailList(List, &Irp->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)
{
Irp = NpRemoveDataQueueEntry(ReadQueue, FALSE, List);
if (Irp)
{
Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
}
}
while (WriteQueue->QueueState == WriteEntries)
{
Irp = NpRemoveDataQueueEntry(WriteQueue, FALSE, List);
if (Irp)
{
Irp->IoStatus.Status = STATUS_PIPE_BROKEN;
InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
}
}
if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
break;
default:
KeBugCheckEx(NPFS_FILE_SYSTEM, 0x1602F9, Ccb->NamedPipeState, 0, 0);
break;
}
return STATUS_SUCCESS;
}