Fix NtSetInformationFile: Cleanup FileCompletionInformation case, use Tag. Use right device object, read FileObject->FinalStatus, use right flags to IO manager can do the cleanup and buffered io semantics, support sync or async waiting
Modified: trunk/reactos/ntoskrnl/io/file.c

Modified: trunk/reactos/ntoskrnl/io/file.c
--- trunk/reactos/ntoskrnl/io/file.c	2005-05-09 02:15:03 UTC (rev 15175)
+++ trunk/reactos/ntoskrnl/io/file.c	2005-05-09 03:02:36 UTC (rev 15176)
@@ -2650,171 +2650,200 @@
                      ULONG Length,
                      FILE_INFORMATION_CLASS FileInformationClass)
 {
-  OBJECT_HANDLE_INFORMATION HandleInformation;
-  PIO_STACK_LOCATION StackPtr;
-  PFILE_OBJECT FileObject;
-  PDEVICE_OBJECT DeviceObject;
-  PIRP Irp;
-  NTSTATUS Status;
-  PVOID SystemBuffer;
-  KPROCESSOR_MODE PreviousMode;
-  BOOLEAN Failed = FALSE;
+    OBJECT_HANDLE_INFORMATION HandleInformation;
+    PIO_STACK_LOCATION StackPtr;
+    PFILE_OBJECT FileObject;
+    PDEVICE_OBJECT DeviceObject;
+    PIRP Irp;
+    KEVENT Event;
+    BOOLEAN LocalEvent = FALSE;
+    NTSTATUS Status = STATUS_SUCCESS;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    BOOLEAN Failed = FALSE;
 
-  ASSERT(IoStatusBlock != NULL);
-  ASSERT(FileInformation != NULL);
+    ASSERT(IoStatusBlock != NULL);
+    ASSERT(FileInformation != NULL);
 
-  DPRINT("NtSetInformationFile(Handle %x StatBlk %x FileInfo %x Length %d "
-         "Class %d)\n", FileHandle, IoStatusBlock, FileInformation,
-         Length, FileInformationClass);
+    DPRINT1("NtSetInformationFile(Handle %x StatBlk %x FileInfo %x Length %d "
+            "Class %d)\n", FileHandle, IoStatusBlock, FileInformation,
+            Length, FileInformationClass);
 
-  PreviousMode = ExGetPreviousMode();
+    /* Get the file object from the file handle */
+    Status = ObReferenceObjectByHandle(FileHandle,
+                                       0,
+                                       IoFileObjectType,
+                                       PreviousMode,
+                                       (PVOID *)&FileObject,
+                                       &HandleInformation);
+    if (!NT_SUCCESS(Status)) return Status;
 
-  /* Get the file object from the file handle */
-  Status = ObReferenceObjectByHandle(FileHandle,
-                                     0,
-                                     IoFileObjectType,
-                                     PreviousMode,
-                                     (PVOID *)&FileObject,
-                                     &HandleInformation);
-  if (!NT_SUCCESS(Status))
-  {
-    return Status;
-  }
+    /* Check information class specific access rights */
+    switch (FileInformationClass)
+    {
+        case FileBasicInformation:
+            if (!(HandleInformation.GrantedAccess & FILE_WRITE_ATTRIBUTES))
+                Failed = TRUE;
+            break;
 
-  /* Check information class specific access rights */
-  switch (FileInformationClass)
-  {
-    case FileBasicInformation:
-      if (!(HandleInformation.GrantedAccess & FILE_WRITE_ATTRIBUTES))
-        Failed = TRUE;
-      break;
+        case FileDispositionInformation:
+            if (!(HandleInformation.GrantedAccess & DELETE))
+                Failed = TRUE;
+            break;
 
-    case FileDispositionInformation:
-      if (!(HandleInformation.GrantedAccess & DELETE))
-        Failed = TRUE;
-      break;
+        case FilePositionInformation:
+            if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) ||
+                !(FileObject->Flags & FO_SYNCHRONOUS_IO))
+                Failed = TRUE;
+            break;
 
-    case FilePositionInformation:
-      if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) ||
-          !(FileObject->Flags & FO_SYNCHRONOUS_IO))
-        Failed = TRUE;
-      break;
+        case FileEndOfFileInformation:
+            if (!(HandleInformation.GrantedAccess & FILE_WRITE_DATA))
+                Failed = TRUE;
+            break;
 
-    case FileEndOfFileInformation:
-      if (!(HandleInformation.GrantedAccess & FILE_WRITE_DATA))
-        Failed = TRUE;
-      break;
+        default:
+            break;
+    }
 
-    default:
-      break;
-  }
+    if (Failed)
+    {
+        DPRINT1("NtSetInformationFile() returns STATUS_ACCESS_DENIED!\n");
+        ObDereferenceObject(FileObject);
+        return STATUS_ACCESS_DENIED;
+    }
 
-  if (Failed)
-  {
-    DPRINT1("NtSetInformationFile() returns STATUS_ACCESS_DENIED!\n");
-    ObDereferenceObject(FileObject);
-    return STATUS_ACCESS_DENIED;
-  }
+    DPRINT("FileObject %x\n", FileObject);
 
-  DPRINT("FileObject %x\n", FileObject);
+    /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
+    /* Handle IO Completion Port quickly */
+    if (FileInformationClass == FileCompletionInformation)
+    {
+        PVOID Queue;
+        PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
+        PIO_COMPLETION_CONTEXT Context;
 
-  /* io completion port? */
-  if (FileInformationClass == FileCompletionInformation)
-  {
-    PKQUEUE Queue;
+        if (Length < sizeof(FILE_COMPLETION_INFORMATION))
+        {
+            Status = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        else
+        {
+            /* Reference the Port */
+            Status = ObReferenceObjectByHandle(CompletionInfo->IoCompletionHandle,
+                                               IO_COMPLETION_MODIFY_STATE,
+                                               ExIoCompletionType,
+                                               PreviousMode,
+                                               (PVOID*)&Queue,
+                                               NULL);
+            if (NT_SUCCESS(Status))
+            {
+                /* Allocate the Context */
+                Context = ExAllocatePoolWithTag(PagedPool, 
+                                                sizeof(IO_COMPLETION_CONTEXT),
+                                                TAG('I', 'o', 'C', 'p'));
+                                            
+                /* Set the Data */
+                Context->Key = CompletionInfo->CompletionKey;
+                Context->Port = Queue;
+                FileObject->CompletionContext = Context;
+            
+                /* Dereference the Port now */
+                ObDereferenceObject(Queue);
+            }
+        }
+    
+        /* Complete the I/O */
+        ObDereferenceObject(FileObject);
+        return Status;
+    }
 
-    if (Length < sizeof(FILE_COMPLETION_INFORMATION))
+    /* Check if this is a direct open or not */
+    if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
     {
-      Status = STATUS_INFO_LENGTH_MISMATCH;
+        DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
     }
     else
     {
-      Status = ObReferenceObjectByHandle(((PFILE_COMPLETION_INFORMATION)FileInformation)->IoCompletionHandle,
-                                         IO_COMPLETION_MODIFY_STATE,//???
-                                         ExIoCompletionType,
-                                         PreviousMode,
-                                         (PVOID*)&Queue,
-                                         NULL);
-      if (NT_SUCCESS(Status))
-      {
-        /* FIXME: maybe use lookaside list */
-        FileObject->CompletionContext = ExAllocatePool(NonPagedPool, sizeof(IO_COMPLETION_CONTEXT));
-        FileObject->CompletionContext->Key = ((PFILE_COMPLETION_INFORMATION)FileInformation)->CompletionKey;
-        FileObject->CompletionContext->Port = Queue;
+        DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    }
+    
+    /* Check if we should use Sync IO or not */
+    if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+    {
+        /* Use File Object event */
+        KeClearEvent(&FileObject->Event);
+    }
+    else
+    {
+        /* Use local event */
+        KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+        LocalEvent = TRUE;
+    }
 
-        ObDereferenceObject(Queue);
-      }
+    /* Allocate the IRP */
+    if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE)))
+    {
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
+    
+    /* Allocate the System Buffer */
+    if (!(Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, 
+                                                                  Length, 
+                                                                  TAG_SYSB)))
+    {
+        IoFreeIrp(Irp);
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    } 
+    
+    /* Copy the data inside */
+    MmSafeCopyFromUser(Irp->AssociatedIrp.SystemBuffer, FileInformation, Length);
 
-    ObDereferenceObject(FileObject);
-    return Status;
-  }
+    /* Set up the IRP */
+    Irp->Tail.Overlay.OriginalFileObject = FileObject;
+    Irp->RequestorMode = PreviousMode;
+    Irp->UserIosb = IoStatusBlock;
+    Irp->UserEvent = (LocalEvent) ? &Event : NULL;
+    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+    Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+    Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
+    
+    /* Set up Stack Data */
+    StackPtr = IoGetNextIrpStackLocation(Irp);
+    StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
+    StackPtr->FileObject = FileObject;
 
-  DeviceObject = FileObject->DeviceObject;
+    /* Set the Parameters */
+    StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
+    StackPtr->Parameters.SetFile.Length = Length;
+    
+    /* Call the Driver */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        if (LocalEvent)
+        {
+            KeWaitForSingleObject(&Event, 
+                                  Executive, 
+                                  PreviousMode, 
+                                  FileObject->Flags & FO_ALERTABLE_IO, 
+                                  NULL);
+            Status = IoStatusBlock->Status;
+        }
+        else
+        {
+            KeWaitForSingleObject(&FileObject->Event,
+                                  Executive, 
+                                  PreviousMode, 
+                                  FileObject->Flags & FO_ALERTABLE_IO, 
+                                  NULL);
+            Status = FileObject->FinalStatus;
+        }
+    }
 
-  Irp = IoAllocateIrp(DeviceObject->StackSize,
-                      TRUE);
-  if (Irp == NULL)
-  {
-    ObDereferenceObject(FileObject);
-    return STATUS_INSUFFICIENT_RESOURCES;
-  }
-
-  SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
-                                       Length,
-                                       TAG_SYSB);
-  if (SystemBuffer == NULL)
-  {
-    IoFreeIrp(Irp);
-    ObDereferenceObject(FileObject);
-    return STATUS_INSUFFICIENT_RESOURCES;
-  }
-
-  MmSafeCopyFromUser(SystemBuffer,
-                     FileInformation,
-                     Length);
-
-  /* Trigger FileObject/Event dereferencing */
-  Irp->Tail.Overlay.OriginalFileObject = FileObject;
-  Irp->RequestorMode = PreviousMode;
-  Irp->AssociatedIrp.SystemBuffer = SystemBuffer;
-  Irp->UserIosb = IoStatusBlock;
-  Irp->UserEvent = &FileObject->Event;
-  KeResetEvent(&FileObject->Event);
-  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
-
-  StackPtr = IoGetNextIrpStackLocation(Irp);
-  StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
-  StackPtr->MinorFunction = 0;
-  StackPtr->Flags = 0;
-  StackPtr->Control = 0;
-  StackPtr->DeviceObject = DeviceObject;
-  StackPtr->FileObject = FileObject;
-
-  StackPtr->Parameters.SetFile.FileInformationClass =
-    FileInformationClass;
-  StackPtr->Parameters.SetFile.Length = Length;
-
-  /*
-   * Pass the IRP to the FSD (and wait for
-   * it if required)
-   */
-  DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
-  Status = IoCallDriver(FileObject->DeviceObject,
-                        Irp);
-  if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
-  {
-    KeWaitForSingleObject(&FileObject->Event,
-                          Executive,
-                          PreviousMode,
-                          FileObject->Flags & FO_ALERTABLE_IO,
-                          NULL);
-    Status = IoStatusBlock->Status;
-  }
-
-  ExFreePool(SystemBuffer);
-
-  return Status;
+    /* Return the Status */
+    return Status;
 }
 
 /*