create.c

来自「一个类似windows」· C语言 代码 · 共 766 行 · 第 1/2 页

C
766
字号
/*
 * 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 ******************************************************************/

#define NDEBUG
#include <debug.h>

#include "npfs.h"

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

static PNPFS_PIPE
NpfsFindPipe(PNPFS_DEVICE_EXTENSION DeviceExt,
	     PUNICODE_STRING PipeName)
{
  PLIST_ENTRY CurrentEntry;
  PNPFS_PIPE Pipe;

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

       CurrentEntry = CurrentEntry->Flink;
     }

  return NULL;
}


static PNPFS_CCB
NpfsFindListeningServerInstance(PNPFS_PIPE Pipe)
{
  PLIST_ENTRY CurrentEntry;
  PNPFS_WAITER_ENTRY Waiter;
  KIRQL oldIrql;
  PIRP Irp;

  CurrentEntry = Pipe->WaiterListHead.Flink;
  while (CurrentEntry != &Pipe->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_PIPE Pipe,
					   PNPFS_CCB Ccb)
{
  PLIST_ENTRY CurrentEntry;
  PNPFS_WAITER_ENTRY Waiter;
  PIRP Irp;

  CurrentEntry = Pipe->WaiterListHead.Flink;
  while (CurrentEntry != &Pipe->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_PIPE Pipe;
  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);
  Pipe = NpfsFindPipe(DeviceExt,
		      &FileObject->FileName);
  if (Pipe == 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(&Pipe->CcbListLock);

  /*
   * Step 2. Create the client CCB.
   */
  ClientCcb = ExAllocatePool(NonPagedPool, sizeof(NPFS_CCB));
  if (ClientCcb == NULL)
    {
      DPRINT("No memory!\n");
      KeUnlockMutex(&Pipe->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->Pipe = Pipe;
  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 (Pipe->OutboundQuota)
    {
      ClientCcb->Data = ExAllocatePool(PagedPool, Pipe->OutboundQuota);
      if (ClientCcb->Data == NULL)
        {
          DPRINT("No memory!\n");
          ExFreePool(ClientCcb);
          KeUnlockMutex(&Pipe->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 = Pipe->OutboundQuota;
  ClientCcb->MaxDataLength = Pipe->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(Pipe);
      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 = Pipe->ServerCcbListHead.Flink;
          while (CurrentEntry != &Pipe->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(&Pipe->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(Pipe, ServerCcb);
        }
    }
  else if (IsListEmpty(&Pipe->ServerCcbListHead))
    {
      DPRINT("No server fcb found!\n");
      KeUnlockMutex(&Pipe->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(&Pipe->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;
    }

  KeUnlockMutex(&Pipe->CcbListLock);

  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_PIPE Pipe;
   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.
    */
   Pipe = NpfsFindPipe(DeviceExt,
		       &FileObject->FileName);
   if (Pipe != NULL)
     {
       /*
        * Found Pipe with the same name. Check if we are
        * allowed to use it.
        */
       KeUnlockMutex(&DeviceExt->PipeListLock);

       if (Pipe->CurrentInstances >= Pipe->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 (Pipe->MaximumInstances != Buffer->MaximumInstances ||
           Pipe->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 + =
减小字号Ctrl + -
显示快捷键?