update for HEAD-2003091401
[reactos.git] / ntoskrnl / io / lock.c
index f27ca8d..35b29ab 100644 (file)
 
 /* INCLUDES *****************************************************************/
 
+
 #include <ddk/ntddk.h>
 
+#define NDEBUG
 #include <internal/debug.h>
 
+
+#define TAG_LOCK                       TAG('F','l','c','k')
+
 /* FUNCTIONS *****************************************************************/
 
 NTSTATUS
 STDCALL
+  NtLockFileCompletionRoutine(
+    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?
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+STDCALL
 NtLockFile (
        IN      HANDLE                  FileHandle,
-       IN      HANDLE                  Event           OPTIONAL,
+       IN      HANDLE                  EventHandle             OPTIONAL,
        IN      PIO_APC_ROUTINE         ApcRoutine      OPTIONAL,
        IN      PVOID                   ApcContext      OPTIONAL,
-       OUT     PIO_STATUS_BLOCK        IoStatusBlock,
+       OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
        IN      PLARGE_INTEGER          ByteOffset,
        IN      PLARGE_INTEGER          Length,
        IN      PULONG                  Key,
@@ -31,19 +52,255 @@ NtLockFile (
        IN      BOOLEAN                 ExclusiveLock
        )
 {
-       UNIMPLEMENTED;
+       NTSTATUS Status;
+       PFILE_OBJECT FileObject = NULL;
+       PLARGE_INTEGER  LocalLength = NULL;
+       PKEVENT Event = NULL;
+       PIRP Irp = NULL;
+       PEXTENDED_IO_STACK_LOCATION StackPtr;
+       IO_STATUS_BLOCK         LocalIoStatusBlock;
+       PIO_STATUS_BLOCK IoStatusBlock;
+       PDEVICE_OBJECT  DeviceObject;
+   ULONG FobFlags;
+
+       //FIXME: instead of this, use SEH when available?
+       if (!Length || !ByteOffset)     {
+               Status = STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       Status = ObReferenceObjectByHandle(
+                                        FileHandle,
+                                    0,
+                                    IoFileObjectType,
+                                    ExGetPreviousMode(),
+                                    (PVOID*)&FileObject,
+                                    NULL);
+
+       if (!NT_SUCCESS(Status)){
+               goto fail;
+       }
+
+       DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+       Irp = IoAllocateIrp(
+                       DeviceObject->StackSize,
+                       TRUE
+                       );
+
+       if (Irp == NULL) {
+               Status = STATUS_INSUFFICIENT_RESOURCES;
+               goto fail;
+       }
+
+       if (EventHandle != NULL && !FailImmediatedly) {
+                Status = ObReferenceObjectByHandle(
+                                        EventHandle,
+                                        SYNCHRONIZE,
+                                        ExEventObjectType,
+                                        ExGetPreviousMode(),
+                                        (PVOID*)&Event,
+                                        NULL);
+
+               if (!NT_SUCCESS(Status)) {
+                       goto fail;
+               }
+
+       }       
+       else {
+               Event = &FileObject->Event;
+               KeResetEvent(Event);
+       }
+
+       if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || FailImmediatedly)
+               IoStatusBlock = &LocalIoStatusBlock;
+       else
+               IoStatusBlock = UserIoStatusBlock;
+
+   //trigger FileObject/Event dereferencing
+   Irp->Tail.Overlay.OriginalFileObject = FileObject;
+
+       Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
+       Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
+
+       Irp->UserEvent = Event;
+       Irp->UserIosb = IoStatusBlock;
+       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+
+       StackPtr = (PEXTENDED_IO_STACK_LOCATION) 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,  
+                                       NtLockFileCompletionRoutine,  
+                                       LocalLength,  
+                                       TRUE,   
+                                       TRUE,  
+                                       TRUE  );
+
+   //can't touch FileObject after IoCallDriver since it might be freed
+   FobFlags = FileObject->Flags;
+       Status = IofCallDriver(DeviceObject, Irp);
+
+   if (Status == STATUS_PENDING && (FobFlags & FO_SYNCHRONOUS_IO)) {
+
+               Status = KeWaitForSingleObject(
+                                                       Event,
+                                                       Executive,
+                                                       ExGetPreviousMode() , 
+                     (FobFlags & FO_ALERTABLE_IO) ? TRUE : FALSE,
+                                                       NULL
+                                                       );
+
+               if (Status != STATUS_WAIT_0) {
+                       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?
+               }
+
+               Status = LocalIoStatusBlock.Status;
+       }
+
+   if (FobFlags & FO_SYNCHRONOUS_IO)
+               *UserIoStatusBlock = LocalIoStatusBlock;
+
+       return Status;
+
+       fail:;
+
+       if (LocalLength) ExFreePool(LocalLength);
+       if (Irp) IoFreeIrp(Irp);
+       if (Event) ObDereferenceObject(Event);
+       if (FileObject) ObDereferenceObject(FileObject);
+
+       return Status;
+
 }
 
 
+
+
+/*
+ * @unimplemented
+ */
 NTSTATUS
 STDCALL
 NtUnlockFile (
        IN      HANDLE                  FileHandle,
-       OUT     PIO_STATUS_BLOCK        IoStatusBlock,
+       OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
        IN      PLARGE_INTEGER          ByteOffset,
        IN      PLARGE_INTEGER          Length,
        OUT     PULONG                  Key             OPTIONAL
        )
 {
-       UNIMPLEMENTED;
+       NTSTATUS Status;
+       PFILE_OBJECT FileObject = NULL;
+       PLARGE_INTEGER  LocalLength = NULL;
+       PIRP Irp  = NULL;
+       PEXTENDED_IO_STACK_LOCATION StackPtr;
+       IO_STATUS_BLOCK         LocalIoStatusBlock;
+       PDEVICE_OBJECT  DeviceObject;
+
+       //FIXME: instead of this, use SEH when available
+       if (!Length || !ByteOffset)     {
+               Status = STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       /*
+       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,
+                                    FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
+                                    IoFileObjectType,
+                                    ExGetPreviousMode(),
+                                    (PVOID*)&FileObject,
+                                    NULL);
+
+       if (!NT_SUCCESS(Status)){
+               goto fail;
+       }
+
+       DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+       Irp = IoAllocateIrp(
+                       DeviceObject->StackSize,
+                       TRUE
+                       );
+
+       if (Irp == NULL) {
+               Status = STATUS_INSUFFICIENT_RESOURCES;
+               goto fail;
+       }
+
+   //trigger FileObject/Event dereferencing
+   Irp->Tail.Overlay.OriginalFileObject = FileObject;
+
+       Irp->UserIosb = &LocalIoStatusBlock;
+       Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+
+       StackPtr = (PEXTENDED_IO_STACK_LOCATION) IoGetNextIrpStackLocation(Irp);
+       StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
+       StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
+       StackPtr->DeviceObject = DeviceObject;
+       StackPtr->FileObject = FileObject;
+
+       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;
+
+       //allways syncronious
+       Status = IofCallDriver(DeviceObject, Irp);
+
+       *UserIoStatusBlock = LocalIoStatusBlock;
+
+       ExFreePool(LocalLength);
+
+       return Status;
+
+       fail:;
+
+       if (LocalLength) ExFreePool(LocalLength);
+       if (Irp) IoFreeIrp(Irp);
+       if (FileObject) ObDereferenceObject(FileObject);
+
+       return Status;
 }