⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 create.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
* COPYRIGHT:  See COPYING in the top level directory
* PROJECT:    ReactOS kernel
* FILE:       drivers/fs/np/create.c
* PURPOSE:    Named pipe filesystem
* PROGRAMMER: David Welch <welch@cwcom.net>
*/

/* INCLUDES ******************************************************************/

#include "npfs.h"

#define NDEBUG
#include <debug.h>

/* FUNCTIONS *****************************************************************/

static PNPFS_FCB
NpfsFindPipe(PNPFS_DEVICE_EXTENSION DeviceExt,
			 PUNICODE_STRING PipeName)
{
	PLIST_ENTRY CurrentEntry;
	PNPFS_FCB Fcb;

	CurrentEntry = DeviceExt->PipeListHead.Flink;
	while (CurrentEntry != &DeviceExt->PipeListHead)
	{
		Fcb = CONTAINING_RECORD(CurrentEntry, NPFS_FCB, PipeListEntry);
		if (RtlCompareUnicodeString(PipeName,
			&Fcb->PipeName,
			TRUE) == 0)
		{
			DPRINT("<%wZ> = <%wZ>\n", PipeName, &Fcb->PipeName);
			return Fcb;
		}

		CurrentEntry = CurrentEntry->Flink;
	}

	return NULL;
}


static PNPFS_CCB
NpfsFindListeningServerInstance(PNPFS_FCB Fcb)
{
	PLIST_ENTRY CurrentEntry;
	PNPFS_WAITER_ENTRY Waiter;
	KIRQL oldIrql;
	PIRP Irp;

	CurrentEntry = Fcb->WaiterListHead.Flink;
	while (CurrentEntry != &Fcb->WaiterListHead)
	{
		Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
		Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
		if (Waiter->Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
		{
			DPRINT("Server found! CCB %p\n", Waiter->Ccb);

			IoAcquireCancelSpinLock(&oldIrql);
			if (!Irp->Cancel)
			{
				(void)IoSetCancelRoutine(Irp, NULL);
				IoReleaseCancelSpinLock(oldIrql);
				return Waiter->Ccb;
			}
			IoReleaseCancelSpinLock(oldIrql);
		}

		CurrentEntry = CurrentEntry->Flink;
	}

	return NULL;
}


static VOID
NpfsSignalAndRemoveListeningServerInstance(PNPFS_FCB Fcb,
										   PNPFS_CCB Ccb)
{
	PLIST_ENTRY CurrentEntry;
	PNPFS_WAITER_ENTRY Waiter;
	PIRP Irp;

	CurrentEntry = Fcb->WaiterListHead.Flink;
	while (CurrentEntry != &Fcb->WaiterListHead)
	{
		Waiter = CONTAINING_RECORD(CurrentEntry, NPFS_WAITER_ENTRY, Entry);
		if (Waiter->Ccb == Ccb)
		{
			DPRINT("Server found! CCB %p\n", Waiter->Ccb);

			RemoveEntryList(&Waiter->Entry);
			Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext);
			Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = 0;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			break;
		}
		CurrentEntry = CurrentEntry->Flink;
	}
}


NTSTATUS STDCALL
NpfsCreate(PDEVICE_OBJECT DeviceObject,
		   PIRP Irp)
{
	PEXTENDED_IO_STACK_LOCATION IoStack;
	PFILE_OBJECT FileObject;
	PNPFS_FCB Fcb;
	PNPFS_CCB ClientCcb;
	PNPFS_CCB ServerCcb = NULL;
	PNPFS_DEVICE_EXTENSION DeviceExt;
	BOOLEAN SpecialAccess;
	ACCESS_MASK DesiredAccess;

	DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp);

	DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
	FileObject = IoStack->FileObject;
	DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess;
	DPRINT("FileObject %p\n", FileObject);
	DPRINT("FileName %wZ\n", &FileObject->FileName);

	Irp->IoStatus.Information = 0;

	SpecialAccess = ((DesiredAccess & SPECIFIC_RIGHTS_ALL) == FILE_READ_ATTRIBUTES);
	if (SpecialAccess)
	{
		DPRINT("NpfsCreate() open client end for special use!\n");
	}

	/*
	* Step 1. Find the pipe we're trying to open.
	*/
	KeLockMutex(&DeviceExt->PipeListLock);
	Fcb = NpfsFindPipe(DeviceExt,
		&FileObject->FileName);
	if (Fcb == NULL)
	{
		/* Not found, bail out with error. */
		DPRINT("No pipe found!\n");
		KeUnlockMutex(&DeviceExt->PipeListLock);
		Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return STATUS_OBJECT_NAME_NOT_FOUND;
	}

	KeUnlockMutex(&DeviceExt->PipeListLock);

	/*
	* Acquire the lock for CCB lists. From now on no modifications to the
	* CCB lists are allowed, because it can cause various misconsistencies.
	*/
	KeLockMutex(&Fcb->CcbListLock);

	/*
	* Step 2. Create the client CCB.
	*/
	ClientCcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
	if (ClientCcb == NULL)
	{
		DPRINT("No memory!\n");
		KeUnlockMutex(&Fcb->CcbListLock);
		Irp->IoStatus.Status = STATUS_NO_MEMORY;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return STATUS_NO_MEMORY;
	}

	ClientCcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
	ClientCcb->Fcb = Fcb;
	ClientCcb->PipeEnd = FILE_PIPE_CLIENT_END;
	ClientCcb->OtherSide = NULL;
	ClientCcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE;
	InitializeListHead(&ClientCcb->ReadRequestListHead);

	DPRINT("CCB: %p\n", ClientCcb);

	/* Initialize data list. */
	if (Fcb->OutboundQuota)
	{
		ClientCcb->Data = ExAllocatePool(PagedPool, Fcb->OutboundQuota);
		if (ClientCcb->Data == NULL)
		{
			DPRINT("No memory!\n");
			ExFreePool(ClientCcb);
			KeUnlockMutex(&Fcb->CcbListLock);
			Irp->IoStatus.Status = STATUS_NO_MEMORY;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			return STATUS_NO_MEMORY;
		}
	}
	else
	{
		ClientCcb->Data = NULL;
	}

	ClientCcb->ReadPtr = ClientCcb->Data;
	ClientCcb->WritePtr = ClientCcb->Data;
	ClientCcb->ReadDataAvailable = 0;
	ClientCcb->WriteQuotaAvailable = Fcb->OutboundQuota;
	ClientCcb->MaxDataLength = Fcb->OutboundQuota;
	ExInitializeFastMutex(&ClientCcb->DataListLock);
	KeInitializeEvent(&ClientCcb->ConnectEvent, SynchronizationEvent, FALSE);
	KeInitializeEvent(&ClientCcb->ReadEvent, SynchronizationEvent, FALSE);
	KeInitializeEvent(&ClientCcb->WriteEvent, SynchronizationEvent, FALSE);


	/*
	* Step 3. Search for listening server CCB.
	*/

	if (!SpecialAccess)
	{
		/*
		* WARNING: Point of no return! Once we get the server CCB it's
		* possible that we completed a wait request and so we have to
		* complete even this request.
		*/

		ServerCcb = NpfsFindListeningServerInstance(Fcb);
		if (ServerCcb == NULL)
		{
			PLIST_ENTRY CurrentEntry;
			PNPFS_CCB Ccb;

			/*
			* If no waiting server CCB was found then try to pick
			* one of the listing server CCB on the pipe.
			*/

			CurrentEntry = Fcb->ServerCcbListHead.Flink;
			while (CurrentEntry != &Fcb->ServerCcbListHead)
			{
				Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry);
				if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
				{
					ServerCcb = Ccb;
					break;
				}
				CurrentEntry = CurrentEntry->Flink;
			}

			/*
			* No one is listening to me?! I'm so lonely... :(
			*/

			if (ServerCcb == NULL)
			{
				/* Not found, bail out with error for FILE_OPEN requests. */
				DPRINT("No listening server CCB found!\n");
				if (ClientCcb->Data)
					ExFreePool(ClientCcb->Data);
				KeUnlockMutex(&Fcb->CcbListLock);
				Irp->IoStatus.Status = STATUS_PIPE_BUSY;
				IoCompleteRequest(Irp, IO_NO_INCREMENT);
				return STATUS_PIPE_BUSY;
			}
		}
		else
		{
			/* Signal the server thread and remove it from the waiter list */
			/* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */
			NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb);
		}
	}
	else if (IsListEmpty(&Fcb->ServerCcbListHead))
	{
		DPRINT("No server fcb found!\n");
		KeUnlockMutex(&Fcb->CcbListLock);
		Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return STATUS_UNSUCCESSFUL;
	}

	/*
	* Step 4. Add the client CCB to a list and connect it if possible.
	*/

	/* Add the client CCB to the pipe CCB list. */
	InsertTailList(&Fcb->ClientCcbListHead, &ClientCcb->CcbListEntry);

	/* Connect to listening server side */
	if (ServerCcb)
	{
		ClientCcb->OtherSide = ServerCcb;
		ServerCcb->OtherSide = ClientCcb;
		ClientCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
		ServerCcb->PipeState = FILE_PIPE_CONNECTED_STATE;
		KeSetEvent(&ServerCcb->ConnectEvent, IO_NO_INCREMENT, FALSE);
	}

	KeUnlockMutex(&Fcb->CcbListLock);

	FileObject->FsContext = Fcb;
	FileObject->FsContext2 = ClientCcb;
	FileObject->Flags |= FO_NAMED_PIPE;

	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	DPRINT("Success!\n");

	return STATUS_SUCCESS;
}


NTSTATUS STDCALL
NpfsCreateNamedPipe(PDEVICE_OBJECT DeviceObject,
					PIRP Irp)
{
	PEXTENDED_IO_STACK_LOCATION IoStack;
	PFILE_OBJECT FileObject;
	PNPFS_DEVICE_EXTENSION DeviceExt;
	PNPFS_FCB Fcb;
	PNPFS_CCB Ccb;
	PNAMED_PIPE_CREATE_PARAMETERS Buffer;
	BOOLEAN NewPipe = FALSE;

	DPRINT("NpfsCreateNamedPipe(DeviceObject %p Irp %p)\n", DeviceObject, Irp);

	DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
	FileObject = IoStack->FileObject;
	DPRINT("FileObject %p\n", FileObject);
	DPRINT("Pipe name %wZ\n", &FileObject->FileName);

	Buffer = IoStack->Parameters.CreatePipe.Parameters;

	Irp->IoStatus.Information = 0;

	if (!(IoStack->Parameters.CreatePipe.ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE)) ||
		(IoStack->Parameters.CreatePipe.ShareAccess & ~(FILE_SHARE_READ|FILE_SHARE_WRITE)))
	{
		Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return STATUS_INVALID_PARAMETER;
	}

	Ccb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
	if (Ccb == NULL)
	{
		Irp->IoStatus.Status = STATUS_NO_MEMORY;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return STATUS_NO_MEMORY;
	}

	Ccb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread;
	KeLockMutex(&DeviceExt->PipeListLock);

	/*
	* First search for existing Pipe with the same name.
	*/
	Fcb = NpfsFindPipe(DeviceExt,
		&FileObject->FileName);
	if (Fcb != NULL)
	{
		/*
		* Found Pipe with the same name. Check if we are
		* allowed to use it.
		*/
		KeUnlockMutex(&DeviceExt->PipeListLock);

		if (Fcb->CurrentInstances >= Fcb->MaximumInstances)
		{
			DPRINT("Out of instances.\n");
			ExFreePool(Ccb);
			Irp->IoStatus.Status = STATUS_PIPE_BUSY;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			return STATUS_PIPE_BUSY;
		}

		/* FIXME: Check pipe modes also! */
		if (Fcb->MaximumInstances != Buffer->MaximumInstances ||
			Fcb->TimeOut.QuadPart != Buffer->DefaultTimeout.QuadPart)
		{
			DPRINT("Asked for invalid pipe mode.\n");
			ExFreePool(Ccb);
			Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			return STATUS_ACCESS_DENIED;
		}
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -