Cleanup ntlock/unlockfile with proper io semantics..same stuff as previous patches
Modified: trunk/reactos/ntoskrnl/io/file.c

Modified: trunk/reactos/ntoskrnl/io/file.c
--- trunk/reactos/ntoskrnl/io/file.c	2005-05-13 19:47:30 UTC (rev 15268)
+++ trunk/reactos/ntoskrnl/io/file.c	2005-05-13 21:07:40 UTC (rev 15269)
@@ -30,18 +30,6 @@
 
 /* INTERNAL FUNCTIONS ********************************************************/
 
-static
-NTSTATUS
-STDCALL
-IopLockFileCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
-                             IN PIRP Irp,
-                             IN PVOID Context)
-{
-  ExFreePool(Context);
-  return STATUS_SUCCESS;
-  // FIXME: Should I call IoFreeIrp and return STATUS_MORE_PROCESSING_REQUIRED?
-}
-
 /*
  * NAME       INTERNAL
  *  IopCreateFile
@@ -1751,159 +1739,141 @@
  */
 NTSTATUS
 STDCALL
-NtLockFile(IN HANDLE   FileHandle,
-           IN HANDLE   EventHandle OPTIONAL,
-           IN PIO_APC_ROUTINE  ApcRoutine OPTIONAL,
-           IN PVOID   ApcContext OPTIONAL,
+NtLockFile(IN HANDLE FileHandle,
+           IN HANDLE EventHandle OPTIONAL,
+           IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+           IN PVOID ApcContext OPTIONAL,
            OUT PIO_STATUS_BLOCK IoStatusBlock,
-           IN PLARGE_INTEGER  ByteOffset,
-           IN PLARGE_INTEGER  Length,
-           IN PULONG   Key,
-           IN BOOLEAN   FailImmediatedly,
-           IN BOOLEAN   ExclusiveLock
- )
+           IN PLARGE_INTEGER ByteOffset,
+           IN PLARGE_INTEGER Length,
+           IN PULONG  Key,
+           IN BOOLEAN FailImmediately,
+           IN BOOLEAN ExclusiveLock)
 {
-  PFILE_OBJECT FileObject = NULL;
-  PLARGE_INTEGER LocalLength = NULL;
-  PKEVENT Event = NULL;
-  PIRP Irp = NULL;
-  PIO_STACK_LOCATION StackPtr;
-  PDEVICE_OBJECT DeviceObject;
-  KPROCESSOR_MODE PreviousMode;
-  NTSTATUS Status;
+    PFILE_OBJECT FileObject = NULL;
+    PLARGE_INTEGER LocalLength = NULL;
+    PIRP Irp = NULL;
+    PIO_STACK_LOCATION StackPtr;
+    PDEVICE_OBJECT DeviceObject;
+    PKEVENT Event = NULL;
+    BOOLEAN LocalEvent = FALSE;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    OBJECT_HANDLE_INFORMATION HandleInformation;
+     
+    /* FIXME: instead of this, use SEH */
+    if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
 
-  // FIXME: instead of this, use SEH when available?
-  if (!Length || !ByteOffset)
-  {
-    Status = STATUS_INVALID_PARAMETER;
-    goto fail;
-  }
+    /* Get File Object */
+    Status = ObReferenceObjectByHandle(FileHandle,
+                                       0,
+                                       IoFileObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&FileObject,
+                                       &HandleInformation);
+    if (!NT_SUCCESS(Status)) return Status;
 
-  PreviousMode = ExGetPreviousMode();
+    /* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
+    if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
+    {
+        DPRINT1("Invalid access rights\n");
+        ObDereferenceObject(FileObject);
+        return STATUS_ACCESS_DENIED;
+    }
 
-  Status = ObReferenceObjectByHandle(FileHandle,
-         0,
-         IoFileObjectType,
-         PreviousMode,
-         (PVOID*)&FileObject,
-         NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    goto fail;
-  }
+    /* Get Event Object */
+    if (EventHandle)
+    {
+        Status = ObReferenceObjectByHandle(EventHandle,
+                                           EVENT_MODIFY_STATE,
+                                           ExEventObjectType,
+                                           PreviousMode,
+                                           (PVOID *)&Event,
+                                           NULL);
+        if (Status != STATUS_SUCCESS) return(Status);
+        KeClearEvent(Event);
+    }
 
-  DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    /* Check if this is a direct open or not */
+    if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
+    {
+        DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
+    }
+    else
+    {
+        DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    }
 
-  Irp = IoAllocateIrp(DeviceObject->StackSize,
-        FALSE);
-  if (Irp == NULL)
-  {
-    Status = STATUS_INSUFFICIENT_RESOURCES;
-    goto fail;
-  }
+    /* Check if we should use Sync IO or not */
+    if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+    {
+        /* Use File Object event */
+        KeClearEvent(&FileObject->Event);
+    }
+    else
+    {
+        LocalEvent = TRUE;
+    }
 
-  if (EventHandle != NULL && !FailImmediatedly)
-  {
-    Status = ObReferenceObjectByHandle(EventHandle,
-           SYNCHRONIZE,
-           ExEventObjectType,
-           PreviousMode,
-           (PVOID*)&Event,
-           NULL);
-    if (!NT_SUCCESS(Status))
+    /* Allocate the IRP */
+    if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
     {
-      goto fail;
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
-  }
-  else
-  {
-    Event = &FileObject->Event;
-    KeResetEvent(Event);
-  }
 
-  /* Trigger FileObject/Event dereferencing */
-  Irp->Tail.Overlay.OriginalFileObject = FileObject;
+    /* Allocate local buffer */  
+    LocalLength = ExAllocatePoolWithTag(NonPagedPool,
+                                        sizeof(LARGE_INTEGER),
+                                        TAG_LOCK);
+    if (!LocalLength)
+    {
+        IoFreeIrp(Irp);
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    *LocalLength = *Length;
+    
+    /* Set up the IRP */
+    Irp->RequestorMode = PreviousMode;
+    Irp->UserIosb = IoStatusBlock;
+    Irp->UserEvent = Event;
+    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+    Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
-  Irp->RequestorMode = PreviousMode;
-  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
-  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
+    /* Set up Stack Data */
+    StackPtr = IoGetNextIrpStackLocation(Irp);
+    StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
+    StackPtr->MinorFunction = IRP_MN_LOCK;
+    StackPtr->FileObject = FileObject;
+    
+    /* Set Parameters */
+    StackPtr->Parameters.LockControl.Length = LocalLength;
+    StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
+    StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
 
-  Irp->UserEvent = Event;
-  Irp->UserIosb = IoStatusBlock;
-  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+    /* Set Flags */
+    if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
+    if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
 
-  StackPtr = IoGetNextIrpStackLocation(Irp);
-  StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
-  StackPtr->MinorFunction = IRP_MN_LOCK;
-  StackPtr->FileObject = FileObject;
-
-  if (ExclusiveLock)
-    StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
-
-  if (FailImmediatedly)
-    StackPtr->Flags |= SL_FAIL_IMMEDIATELY;
-
-  LocalLength = ExAllocatePoolWithTag(NonPagedPool,
-          sizeof(LARGE_INTEGER),
-          TAG_LOCK);
-  if (!LocalLength)
-  {
-    Status = STATUS_INSUFFICIENT_RESOURCES;
-    goto fail;
-  }
-
-  *LocalLength = *Length;
-
-  StackPtr->Parameters.LockControl.Length = LocalLength;
-  StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
-  StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
-
-  IoSetCompletionRoutine(Irp,
-    IopLockFileCompletionRoutine,
-    LocalLength,
-    TRUE,
-    TRUE,
-    TRUE);
-
-  /* Can't touch FileObject after IoCallDriver since it might be freed */
-  Status = IofCallDriver(DeviceObject, Irp);
-  if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
-  {
-    Status = KeWaitForSingleObject(Event,
-       Executive,
-       PreviousMode,
-       FileObject->Flags & FO_ALERTABLE_IO,
-       NULL);
-
-    if (Status != STATUS_WAIT_0)
+    /* Call the Driver */
+    FileObject->LockOperation = TRUE;
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
     {
-      DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n");
-      /*
-       * FIXME: Should do some special processing here if alertable wait
-       * was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC)
-       */
-      return Status; /* Set status to something else? */
+        if (!LocalEvent)
+        {
+            KeWaitForSingleObject(&FileObject->Event,
+                                  Executive,
+                                  PreviousMode,
+                                  FileObject->Flags & FO_ALERTABLE_IO,
+                                  NULL);
+            Status = FileObject->FinalStatus;
+        }
     }
 
-    Status = IoStatusBlock->Status;
-  }
-
-  return Status;
-
-fail:;
-  if (LocalLength)
-    ExFreePool(LocalLength);
-
-  if (Irp)
-    IoFreeIrp(Irp);
-
-  if (Event)
-    ObDereferenceObject(Event);
-
-  if (FileObject)
-    ObDereferenceObject(FileObject);
-
-  return Status;
+    /* Return the Status */
+    return Status;
 }
 
 /*
@@ -2865,93 +2835,124 @@
              IN  PLARGE_INTEGER Length,
              OUT PULONG Key OPTIONAL)
 {
-  PFILE_OBJECT FileObject = NULL;
-  PLARGE_INTEGER LocalLength = NULL;
-  PIRP Irp = NULL;
-  PIO_STACK_LOCATION StackPtr;
-  PDEVICE_OBJECT DeviceObject;
-  KPROCESSOR_MODE PreviousMode;
-  NTSTATUS Status;
+    PFILE_OBJECT FileObject = NULL;
+    PLARGE_INTEGER LocalLength = NULL;
+    PIRP Irp = NULL;
+    PIO_STACK_LOCATION StackPtr;
+    PDEVICE_OBJECT DeviceObject;
+    KEVENT Event;
+    BOOLEAN LocalEvent = FALSE;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    OBJECT_HANDLE_INFORMATION HandleInformation;
+     
+    /* FIXME: instead of this, use SEH */
+    if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
 
-  // FIXME: instead of this, use SEH when available
-  if (!Length || !ByteOffset)
-  {
-    Status = STATUS_INVALID_PARAMETER;
-    goto fail;
-  }
+    /* Get File Object */
+    Status = ObReferenceObjectByHandle(FileHandle,
+                                       0,
+                                       IoFileObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&FileObject,
+                                       &HandleInformation);
+    if (!NT_SUCCESS(Status)) return Status;
 
-  PreviousMode = ExGetPreviousMode();
+    /* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
+    if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
+    {
+        DPRINT1("Invalid access rights\n");
+        ObDereferenceObject(FileObject);
+        return STATUS_ACCESS_DENIED;
+    }
 
-  /*
-   * BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
-   * It should ONLY fail if we desire an access that conflict with granted access!
-   */
-  Status = ObReferenceObjectByHandle(FileHandle,
-         0, //FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
-         IoFileObjectType,
-         PreviousMode,
-         (PVOID*)&FileObject,
-         NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    goto fail;
-  }
+    /* Check if this is a direct open or not */
+    if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
+    {
+        DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
+    }
+    else
+    {
+        DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    }
 
-  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;
+    }
 
-  Irp = IoAllocateIrp(DeviceObject->StackSize,
-        FALSE);
-  if (Irp == NULL)
-  {
-    Status = STATUS_INSUFFICIENT_RESOURCES;
-    goto fail;
-  }
+    /* Allocate the IRP */
+    if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
+    {
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-  /* Trigger FileObject/Event dereferencing */
-  Irp->Tail.Overlay.OriginalFileObject = FileObject;
-  Irp->RequestorMode = PreviousMode;
-  Irp->UserIosb = IoStatusBlock;
-  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+    /* Allocate local buffer */  
+    LocalLength = ExAllocatePoolWithTag(NonPagedPool,
+                                        sizeof(LARGE_INTEGER),
+                                        TAG_LOCK);
+    if (!LocalLength)
+    {
+        IoFreeIrp(Irp);
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    *LocalLength = *Length;
+    
+    /* Set up the IRP */
+    Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
+    Irp->RequestorMode = PreviousMode;
+    Irp->UserIosb = IoStatusBlock;
+    Irp->UserEvent = (LocalEvent) ? &Event : NULL;
+    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+    Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
-  StackPtr = IoGetNextIrpStackLocation(Irp);
-  StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
-  StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
-  StackPtr->DeviceObject = DeviceObject;
-  StackPtr->FileObject = FileObject;
+    /* Set up Stack Data */
+    StackPtr = IoGetNextIrpStackLocation(Irp);
+    StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
+    StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
+    StackPtr->FileObject = FileObject;
+    
+    /* Set Parameters */
+    StackPtr->Parameters.LockControl.Length = LocalLength;
+    StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
+    StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
 
-  LocalLength = ExAllocatePoolWithTag(NonPagedPool,
-          sizeof(LARGE_INTEGER),
-          TAG_LOCK);
-  if (!LocalLength)
-  {
-    Status = STATUS_INSUFFICIENT_RESOURCES;
-    goto fail;
-  }
+    /* 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;
+        }
+    }
 
-  *LocalLength = *Length;
-
-  StackPtr->Parameters.LockControl.Length = LocalLength;
-  StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
-  StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
-
-  /* Allways synchronous */
-  Status = IofCallDriver(DeviceObject, Irp);
-
-  ExFreePool(LocalLength);
-
-  return Status;
-
-fail:;
-  if (LocalLength)
-    ExFreePool(LocalLength);
-
-  if (Irp)
-    IoFreeIrp(Irp);
-
-  if (FileObject)
-    ObDereferenceObject(FileObject);
-
-  return Status;
+    /* Return the Status */
+    return Status;
 }
 
 /*