Cleanup isn't necessary after calling the driver in NtQueryDirectoryFile.
[reactos.git] / reactos / ntoskrnl / io / file.c
index b2d17f2..c8107ff 100644 (file)
@@ -755,10 +755,11 @@ IoCreateFile(OUT PHANDLE  FileHandle,
    IO_SECURITY_CONTEXT  SecurityContext;
    KPROCESSOR_MODE      AccessMode;
    HANDLE               LocalHandle;
-   IO_STATUS_BLOCK      LocalIoStatusBlock;
    LARGE_INTEGER        SafeAllocationSize;
    PVOID                SystemEaBuffer = NULL;
    NTSTATUS  Status = STATUS_SUCCESS;
+   AUX_DATA AuxData;
+   ACCESS_STATE AccessState;
 
    DPRINT("IoCreateFile(FileHandle 0x%p, DesiredAccess %x, "
           "ObjectAttributes 0x%p ObjectAttributes->ObjectName->Buffer %S)\n",
@@ -963,8 +964,14 @@ IoCreateFile(OUT PHANDLE  FileHandle,
    if (CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
      FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
 
+    /* 
+     * FIXME: We should get the access state from Ob once this function becomes
+     * a parse routine once the Ob is refactored.
+     */
+   SeCreateAccessState(&AccessState, &AuxData, FILE_ALL_ACCESS, NULL);
+
    SecurityContext.SecurityQos = NULL; /* ?? */
-   SecurityContext.AccessState = NULL; /* ?? */
+   SecurityContext.AccessState = &AccessState;
    SecurityContext.DesiredAccess = DesiredAccess;
    SecurityContext.FullCreateOptions = 0; /* ?? */
 
@@ -988,7 +995,7 @@ IoCreateFile(OUT PHANDLE  FileHandle,
    //trigger FileObject/Event dereferencing
    Irp->Tail.Overlay.OriginalFileObject = FileObject;
    Irp->RequestorMode = AccessMode;
-   Irp->UserIosb = &LocalIoStatusBlock;
+   Irp->UserIosb = IoStatusBlock;
    Irp->AssociatedIrp.SystemBuffer = SystemEaBuffer;
    Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
@@ -1054,7 +1061,7 @@ IoCreateFile(OUT PHANDLE  FileHandle,
                              AccessMode,
                              FALSE,
                              NULL);
-       Status = LocalIoStatusBlock.Status;
+       Status = IoStatusBlock->Status;
      }
    if (!NT_SUCCESS(Status))
      {
@@ -1069,7 +1076,6 @@ IoCreateFile(OUT PHANDLE  FileHandle,
        _SEH_TRY
          {
            *FileHandle = LocalHandle;
-           *IoStatusBlock = LocalIoStatusBlock;
          }
        _SEH_HANDLE
          {
@@ -1380,20 +1386,41 @@ STDCALL
 NtCancelIoFile(IN HANDLE FileHandle,
                OUT PIO_STATUS_BLOCK IoStatusBlock)
 {
-   NTSTATUS Status;
    PFILE_OBJECT FileObject;
    PETHREAD Thread;
    PIRP Irp;
    KIRQL OldIrql;
    BOOLEAN OurIrpsInList = FALSE;
    LARGE_INTEGER Interval;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   PAGED_CODE();
+
+   PreviousMode = KeGetPreviousMode();
+
+   if (PreviousMode != KernelMode)
+   {
+      _SEH_TRY
+      {
+         ProbeForWrite(IoStatusBlock,
+                       sizeof(IO_STATUS_BLOCK),
+                       sizeof(ULONG));
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
 
-   if ((ULONG_PTR)IoStatusBlock >= (ULONG_PTR)MmUserProbeAddress &&
-       KeGetPreviousMode() != KernelMode)
-      return STATUS_ACCESS_VIOLATION;
+      if (!NT_SUCCESS(Status)) return Status;
+   }
 
-   Status = ObReferenceObjectByHandle(FileHandle, 0, IoFileObjectType,
-                                      KeGetPreviousMode(), (PVOID*)&FileObject,
+   Status = ObReferenceObjectByHandle(FileHandle,
+                                      0,
+                                      IoFileObjectType,
+                                      PreviousMode,
+                                      (PVOID*)&FileObject,
                                       NULL);
    if (!NT_SUCCESS(Status))
       return Status;
@@ -1531,23 +1558,39 @@ NtCreateMailslotFile(OUT PHANDLE FileHandle,
     MAILSLOT_CREATE_PARAMETERS Buffer;
 
     DPRINT("NtCreateMailslotFile(FileHandle 0x%p, DesiredAccess %x, "
-           "ObjectAttributes 0x%p ObjectAttributes->ObjectName->Buffer %S)\n",
-           FileHandle,DesiredAccess,ObjectAttributes,
-           ObjectAttributes->ObjectName->Buffer);
+           "ObjectAttributes 0x%p)\n",
+           FileHandle,DesiredAccess,ObjectAttributes);
+
     PAGED_CODE();
 
     /* Check for Timeout */
-    if (TimeOut)
+    if (TimeOut != NULL)
     {
-        /* Enable it */
-        Buffer.TimeoutSpecified = TRUE;
+        if (KeGetPreviousMode() != KernelMode)
+        {
+            NTSTATUS Status = STATUS_SUCCESS;
+
+            _SEH_TRY
+            {
+                Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
+            }
+            _SEH_HANDLE
+            {
+                Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+
+            if (!NT_SUCCESS(Status)) return Status;
+        }
+        else
+        {
+            Buffer.ReadTimeout = *TimeOut;
+        }
 
-        /* FIXME: Add SEH */
-        Buffer.ReadTimeout = *TimeOut;
+        Buffer.TimeoutSpecified = TRUE;
     }
     else
     {
-        /* No timeout */
         Buffer.TimeoutSpecified = FALSE;
     }
 
@@ -1592,25 +1635,39 @@ NtCreateNamedPipeFile(PHANDLE FileHandle,
     NAMED_PIPE_CREATE_PARAMETERS Buffer;
 
     DPRINT("NtCreateNamedPipeFile(FileHandle 0x%p, DesiredAccess %x, "
-           "ObjectAttributes 0x%p ObjectAttributes->ObjectName->Buffer %S)\n",
-            FileHandle,DesiredAccess,ObjectAttributes,
-            ObjectAttributes->ObjectName->Buffer);
+           "ObjectAttributes 0x%p)\n",
+            FileHandle,DesiredAccess,ObjectAttributes);
+
     PAGED_CODE();
 
     /* Check for Timeout */
-    if (DefaultTimeout)
+    if (DefaultTimeout != NULL)
     {
-        /* Enable it */
-        Buffer.TimeoutSpecified = TRUE;
+        if (KeGetPreviousMode() != KernelMode)
+        {
+            NTSTATUS Status = STATUS_SUCCESS;
+
+            _SEH_TRY
+            {
+                Buffer.DefaultTimeout = ProbeForReadLargeInteger(DefaultTimeout);
+            }
+            _SEH_HANDLE
+            {
+                Status = _SEH_GetExceptionCode();
+            }
+            _SEH_END;
+
+            if (!NT_SUCCESS(Status)) return Status;
+        }
+        else
+        {
+            Buffer.DefaultTimeout = *DefaultTimeout;
+        }
 
-        /* FIXME: Add SEH */
-        Buffer.DefaultTimeout = *DefaultTimeout;
+        Buffer.TimeoutSpecified = TRUE;
     }
     else
-    {
-        /* No timeout */
         Buffer.TimeoutSpecified = FALSE;
-    }
 
     /* Set Settings */
     Buffer.NamedPipeType = NamedPipeType;
@@ -1724,6 +1781,8 @@ NTSTATUS
 STDCALL
 NtFlushWriteBuffer(VOID)
 {
+    PAGED_CODE();
+
     KeFlushWriteBuffer();
     return STATUS_SUCCESS;
 }
@@ -1746,20 +1805,56 @@ NtFlushBuffersFile(IN  HANDLE FileHandle,
     PFILE_OBJECT FileObject = NULL;
     PIRP Irp;
     PIO_STACK_LOCATION StackPtr;
-    NTSTATUS Status;
+    NTSTATUS Status = STATUS_SUCCESS;
     PDEVICE_OBJECT DeviceObject;
     KEVENT Event;
     BOOLEAN LocalEvent = FALSE;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
+    OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
+    KPROCESSOR_MODE PreviousMode;
+
+    PAGED_CODE();
+
+    PreviousMode = KeGetPreviousMode();
+
+    if (PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            ProbeForWrite(IoStatusBlock,
+                          sizeof(IO_STATUS_BLOCK),
+                          sizeof(ULONG));
+        }
+        _SEH_HANDLE
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if (!NT_SUCCESS(Status)) return Status;
+    }
 
     /* Get the File Object */
     Status = ObReferenceObjectByHandle(FileHandle,
-                                       FILE_WRITE_DATA,
-                                       NULL,
+                                       0,
+                                       IoFileObjectType,
                                        PreviousMode,
                                        (PVOID*)&FileObject,
-                                       NULL);
-    if (Status != STATUS_SUCCESS) return(Status);
+                                       &ObjectHandleInfo);
+    if (!NT_SUCCESS(Status)) return(Status);
+
+    /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
+       granted. However, if this is a named pipe, make sure we don't ask for
+       FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
+       access right! */
+    if (!(FileObject->Flags & FO_NAMED_PIPE))
+        DesiredAccess |= FILE_APPEND_DATA;
+    if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess,
+                                  DesiredAccess))
+    {
+        ObDereferenceObject(FileObject);
+        return STATUS_ACCESS_DENIED;
+    }
 
     /* Check if this is a direct open or not */
     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
@@ -1968,12 +2063,17 @@ NtLockFile(IN HANDLE FileHandle,
     PDEVICE_OBJECT DeviceObject;
     PKEVENT Event = NULL;
     BOOLEAN LocalEvent = FALSE;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    KPROCESSOR_MODE PreviousMode;
+    LARGE_INTEGER CapturedByteOffset, CapturedLength;
     NTSTATUS Status = STATUS_SUCCESS;
     OBJECT_HANDLE_INFORMATION HandleInformation;
-     
-    /* FIXME: instead of this, use SEH */
-    if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
+
+    PAGED_CODE();
+
+    PreviousMode = KeGetPreviousMode();
+
+    CapturedByteOffset.QuadPart = 0;
+    CapturedLength.QuadPart = 0;
 
     /* Get File Object */
     Status = ObReferenceObjectByHandle(FileHandle,
@@ -1984,12 +2084,41 @@ NtLockFile(IN HANDLE FileHandle,
                                        &HandleInformation);
     if (!NT_SUCCESS(Status)) return Status;
 
-    /* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
-    if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
+    if (PreviousMode != KernelMode)
     {
-        DPRINT1("Invalid access rights\n");
-        ObDereferenceObject(FileObject);
-        return STATUS_ACCESS_DENIED;
+        /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access unless
+           we're in KernelMode! */
+        if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
+        {
+            DPRINT1("Invalid access rights\n");
+            ObDereferenceObject(FileObject);
+            return STATUS_ACCESS_DENIED;
+        }
+
+        _SEH_TRY
+        {
+            ProbeForWrite(IoStatusBlock,
+                          sizeof(IO_STATUS_BLOCK),
+                          sizeof(ULONG));
+            CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
+            CapturedLength = ProbeForReadLargeInteger(Length);
+        }
+        _SEH_HANDLE
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if (!NT_SUCCESS(Status))
+        {
+            ObDereferenceObject(FileObject);
+            return Status;
+        }
+    }
+    else
+    {
+        CapturedByteOffset = *ByteOffset;
+        CapturedLength = *Length;
     }
 
     /* Get Event Object */
@@ -2043,7 +2172,7 @@ NtLockFile(IN HANDLE FileHandle,
         ObDereferenceObject(FileObject);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-    *LocalLength = *Length;
+    *LocalLength = CapturedLength;
     
     /* Set up the IRP */
     Irp->RequestorMode = PreviousMode;
@@ -2060,8 +2189,8 @@ NtLockFile(IN HANDLE FileHandle,
     
     /* Set Parameters */
     StackPtr->Parameters.LockControl.Length = LocalLength;
-    StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
-    StackPtr->Parameters.LockControl.Key = Key ? Key : 0;
+    StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
+    StackPtr->Parameters.LockControl.Key = Key;
 
     /* Set Flags */
     if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
@@ -2270,6 +2399,20 @@ NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
                                   FileInformation);
 }
 
+static NTSTATUS NTAPI
+IopQueryDirectoryFileCompletion(IN PDEVICE_OBJECT DeviceObject,
+                               IN PIRP Irp,
+                               IN PVOID Context)
+{
+    ASSERT (Context);
+
+    DPRINT("IopQueryDirectoryFileCompletion was called for \'%wZ\'\n", Context);
+
+    ExFreePool(Context);
+
+    return STATUS_SUCCESS;
+}
+
 
 /*
  * @implemented
@@ -2315,12 +2458,13 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
 {
     PIRP Irp;
     PDEVICE_OBJECT DeviceObject;
-    PFILE_OBJECT FileObject;
+    PFILE_OBJECT FileObject = NULL;
     PIO_STACK_LOCATION StackPtr;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status = STATUS_SUCCESS;
     BOOLEAN LocalEvent = FALSE;
     PKEVENT Event = NULL;
+    PUNICODE_STRING SearchPattern = NULL;
 
     DPRINT("NtQueryDirectoryFile()\n");
     PAGED_CODE();
@@ -2336,6 +2480,24 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
             ProbeForWrite(FileInformation,
                           Length,
                           sizeof(ULONG));
+            if (FileName)
+            {
+                UNICODE_STRING CapturedFileName;
+
+                CapturedFileName = ProbeForReadUnicodeString(FileName);
+                ProbeForRead(CapturedFileName.Buffer,
+                             CapturedFileName.MaximumLength,
+                             1);
+                SearchPattern = ExAllocatePool(NonPagedPool, CapturedFileName.Length + sizeof(WCHAR) + sizeof(UNICODE_STRING));
+                if (SearchPattern == NULL)
+                {
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+                    _SEH_LEAVE;
+                }
+                SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)SearchPattern + sizeof(UNICODE_STRING));
+                SearchPattern->MaximumLength = CapturedFileName.Length + sizeof(WCHAR);
+                RtlCopyUnicodeString(SearchPattern, &CapturedFileName);
+            }
         }
         _SEH_HANDLE
         {
@@ -2343,7 +2505,10 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
         }
         _SEH_END;
 
-        if(!NT_SUCCESS(Status)) return Status;
+        if(!NT_SUCCESS(Status)) 
+        {
+            goto Cleanup;
+        }
     }
 
     /* Get File Object */
@@ -2353,7 +2518,10 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
                                        PreviousMode,
                                        (PVOID *)&FileObject,
                                        NULL);
-    if (Status != STATUS_SUCCESS) return(Status);
+    if (!NT_SUCCESS(Status))
+    {
+       goto Cleanup;
+    }
 
     /* Get Event Object */
     if (PEvent)
@@ -2364,7 +2532,11 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
                                            PreviousMode,
                                            (PVOID *)&Event,
                                            NULL);
-        if (Status != STATUS_SUCCESS) return(Status);
+        if (!NT_SUCCESS(Status)) 
+        {
+            goto Cleanup;
+        }
+
         KeClearEvent(Event);
     }
 
@@ -2392,8 +2564,8 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
     /* Allocate the IRP */
     if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE)))
     {
-        ObDereferenceObject(FileObject);
-        return STATUS_INSUFFICIENT_RESOURCES;
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
     }
 
     /* Set up the IRP */
@@ -2414,13 +2586,23 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
 
     /* Set Parameters */
     StackPtr->Parameters.QueryDirectory.FileInformationClass = FileInformationClass;
-    StackPtr->Parameters.QueryDirectory.FileName = FileName;
+    StackPtr->Parameters.QueryDirectory.FileName = SearchPattern ? SearchPattern : FileName;
     StackPtr->Parameters.QueryDirectory.FileIndex = 0;
     StackPtr->Parameters.QueryDirectory.Length = Length;
     StackPtr->Flags = 0;
     if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
     if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
 
+    if (SearchPattern)
+    {
+        IoSetCompletionRoutine(Irp,
+                               IopQueryDirectoryFileCompletion,
+                              SearchPattern,
+                              TRUE,
+                              TRUE,
+                              TRUE);
+    }
+
     /* Call the Driver */
     Status = IoCallDriver(DeviceObject, Irp);
     if (Status == STATUS_PENDING)
@@ -2436,6 +2618,23 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
         }
     }
 
+
+    return Status;
+
+Cleanup:
+    if (FileObject != NULL)
+    {
+        ObDereferenceObject(FileObject);
+    }
+    if (Event != NULL)
+    {
+        ObDereferenceObject(Event);
+    }
+    if (SearchPattern != NULL)
+    {
+        ExFreePool(SearchPattern);
+    }
+
     /* Return the Status */
     return Status;
 }
@@ -2709,7 +2908,7 @@ NtReadFile(IN HANDLE FileHandle,
            OUT PIO_STATUS_BLOCK IoStatusBlock,
            OUT PVOID Buffer,
            IN ULONG Length,
-           IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
+           IN PLARGE_INTEGER ByteOffset OPTIONAL,
            IN PULONG Key OPTIONAL)
 {
     NTSTATUS Status = STATUS_SUCCESS;
@@ -2717,14 +2916,19 @@ NtReadFile(IN HANDLE FileHandle,
     PIRP Irp = NULL;
     PDEVICE_OBJECT DeviceObject;
     PIO_STACK_LOCATION StackPtr;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    KPROCESSOR_MODE PreviousMode;
     BOOLEAN LocalEvent = FALSE;
     PKEVENT EventObject = NULL;
+    LARGE_INTEGER CapturedByteOffset;
 
     DPRINT("NtReadFile(FileHandle 0x%p Buffer 0x%p Length %x ByteOffset 0x%p, "
            "IoStatusBlock 0x%p)\n", FileHandle, Buffer, Length, ByteOffset,
             IoStatusBlock);
+
     PAGED_CODE();
+    
+    PreviousMode = KeGetPreviousMode();
+    CapturedByteOffset.QuadPart = 0;
 
     /* Validate User-Mode Buffers */
     if(PreviousMode != KernelMode)
@@ -2734,11 +2938,14 @@ NtReadFile(IN HANDLE FileHandle,
             ProbeForWrite(IoStatusBlock,
                           sizeof(IO_STATUS_BLOCK),
                           sizeof(ULONG));
-            #if 0
             ProbeForWrite(Buffer,
                           Length,
-                          sizeof(ULONG));
-            #endif
+                          1);
+            if (ByteOffset != NULL)
+            {
+                CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
+            }
+            /* FIXME - probe other pointers and capture information */
         }
         _SEH_HANDLE
         {
@@ -2748,6 +2955,13 @@ NtReadFile(IN HANDLE FileHandle,
 
         if(!NT_SUCCESS(Status)) return Status;
     }
+    else
+    {
+        if (ByteOffset != NULL)
+        {
+            CapturedByteOffset = *ByteOffset;
+        }
+    }
 
     /* Get File Object */
     Status = ObReferenceObjectByHandle(FileHandle,
@@ -2759,9 +2973,9 @@ NtReadFile(IN HANDLE FileHandle,
     if (!NT_SUCCESS(Status)) return Status;
 
     /* Check the Byte Offset */
-    if (!ByteOffset ||
-        (ByteOffset->u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
-         ByteOffset->u.HighPart == -1))
+    if (ByteOffset == NULL ||
+        (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
+         CapturedByteOffset.u.HighPart == -1))
     {
         /* a valid ByteOffset is required if asynch. op. */
         if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
@@ -2772,7 +2986,7 @@ NtReadFile(IN HANDLE FileHandle,
         }
 
         /* Use the Current Byte OFfset */
-        ByteOffset = &FileObject->CurrentByteOffset;
+        CapturedByteOffset = FileObject->CurrentByteOffset;
     }
 
     /* Check for event */
@@ -2821,7 +3035,7 @@ NtReadFile(IN HANDLE FileHandle,
                                            DeviceObject,
                                            Buffer,
                                            Length,
-                                           ByteOffset,
+                                           &CapturedByteOffset,
                                            EventObject,
                                            IoStatusBlock);
         if (Irp == NULL)
@@ -3276,7 +3490,7 @@ NtUnlockFile(IN  HANDLE FileHandle,
              OUT PIO_STATUS_BLOCK IoStatusBlock,
              IN  PLARGE_INTEGER ByteOffset,
              IN  PLARGE_INTEGER Length,
-             OUT ULONG Key OPTIONAL)
+             IN  ULONG Key OPTIONAL)
 {
     PFILE_OBJECT FileObject = NULL;
     PLARGE_INTEGER LocalLength = NULL;
@@ -3285,12 +3499,17 @@ NtUnlockFile(IN  HANDLE FileHandle,
     PDEVICE_OBJECT DeviceObject;
     KEVENT Event;
     BOOLEAN LocalEvent = FALSE;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    KPROCESSOR_MODE PreviousMode;
     NTSTATUS Status = STATUS_SUCCESS;
+    LARGE_INTEGER CapturedByteOffset, CapturedLength;
     OBJECT_HANDLE_INFORMATION HandleInformation;
-     
-    /* FIXME: instead of this, use SEH */
-    if (!Length || !ByteOffset) return STATUS_INVALID_PARAMETER;
+
+    PAGED_CODE();
+
+    PreviousMode = KeGetPreviousMode();
+
+    CapturedByteOffset.QuadPart = 0;
+    CapturedLength.QuadPart = 0;
 
     /* Get File Object */
     Status = ObReferenceObjectByHandle(FileHandle,
@@ -3301,12 +3520,41 @@ NtUnlockFile(IN  HANDLE FileHandle,
                                        &HandleInformation);
     if (!NT_SUCCESS(Status)) return Status;
 
-    /* Must have FILE_READ_DATA | FILE_WRITE_DATA access */
-    if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
+    if (PreviousMode != KernelMode)
     {
-        DPRINT1("Invalid access rights\n");
-        ObDereferenceObject(FileObject);
-        return STATUS_ACCESS_DENIED;
+        /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access unless we're
+           in KernelMode! */
+        if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_READ_DATA)))
+        {
+            DPRINT1("Invalid access rights\n");
+            ObDereferenceObject(FileObject);
+            return STATUS_ACCESS_DENIED;
+        }
+
+        _SEH_TRY
+        {
+            ProbeForWrite(IoStatusBlock,
+                          sizeof(IO_STATUS_BLOCK),
+                          sizeof(ULONG));
+            CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
+            CapturedLength = ProbeForReadLargeInteger(Length);
+        }
+        _SEH_HANDLE
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if (!NT_SUCCESS(Status))
+        {
+            ObDereferenceObject(FileObject);
+            return Status;
+        }
+    }
+    else
+    {
+        CapturedByteOffset = *ByteOffset;
+        CapturedLength = *Length;
     }
 
     /* Check if this is a direct open or not */
@@ -3349,7 +3597,7 @@ NtUnlockFile(IN  HANDLE FileHandle,
         ObDereferenceObject(FileObject);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-    *LocalLength = *Length;
+    *LocalLength = CapturedLength;
     
     /* Set up the IRP */
     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
@@ -3367,8 +3615,8 @@ NtUnlockFile(IN  HANDLE FileHandle,
     
     /* Set Parameters */
     StackPtr->Parameters.LockControl.Length = LocalLength;
-    StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
-    StackPtr->Parameters.LockControl.Key = Key ? Key : 0;
+    StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
+    StackPtr->Parameters.LockControl.Key = Key;
 
     /* Call the Driver */
     Status = IoCallDriver(DeviceObject, Irp);
@@ -3424,34 +3672,49 @@ NtWriteFile (IN HANDLE FileHandle,
              IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
              IN PULONG Key OPTIONAL)
 {
-    OBJECT_HANDLE_INFORMATION HandleInformation;
+    OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
     NTSTATUS Status = STATUS_SUCCESS;
     PFILE_OBJECT FileObject;
     PIRP Irp = NULL;
     PDEVICE_OBJECT DeviceObject;
     PIO_STACK_LOCATION StackPtr;
-    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    KPROCESSOR_MODE PreviousMode;
     BOOLEAN LocalEvent = FALSE;
     PKEVENT EventObject = NULL;
+    LARGE_INTEGER CapturedByteOffset;
+    ULONG CapturedKey = 0;
+    ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
 
     DPRINT("NtWriteFile(FileHandle 0x%p Buffer 0x%p Length %x ByteOffset 0x%p, "
             "IoStatusBlock 0x%p)\n", FileHandle, Buffer, Length, ByteOffset,
             IoStatusBlock);
 
+    PAGED_CODE();
+
+    PreviousMode = KeGetPreviousMode();
+    CapturedByteOffset.QuadPart = 0;
+
     /* Validate User-Mode Buffers */
     if(PreviousMode != KernelMode)
     {
         _SEH_TRY
         {
-            #if 0
             ProbeForWrite(IoStatusBlock,
                           sizeof(IO_STATUS_BLOCK),
                           sizeof(ULONG));
 
             ProbeForRead(Buffer,
                          Length,
-                         sizeof(ULONG));
-            #endif
+                         1);
+            if (ByteOffset != NULL)
+            {
+                CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
+            }
+
+            if (Key != NULL)
+            {
+                CapturedKey = ProbeForReadUlong(Key);
+            }
         }
         _SEH_HANDLE
         {
@@ -3461,6 +3724,17 @@ NtWriteFile (IN HANDLE FileHandle,
 
         if(!NT_SUCCESS(Status)) return Status;
     }
+    else
+    {
+        if (ByteOffset != NULL)
+        {
+            CapturedByteOffset = *ByteOffset;
+        }
+        if (Key != NULL)
+        {
+            CapturedKey = *Key;
+        }
+    }
 
     /* Get File Object */
     Status = ObReferenceObjectByHandle(FileHandle,
@@ -3468,24 +3742,29 @@ NtWriteFile (IN HANDLE FileHandle,
                                        IoFileObjectType,
                                        PreviousMode,
                                        (PVOID*)&FileObject,
-                                       &HandleInformation);
+                                       &ObjectHandleInfo);
     if (!NT_SUCCESS(Status)) return Status;
 
-    /* Must have FILE_WRITE_DATA | FILE_APPEND_DATA access */
-    if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+    /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
+       granted. However, if this is a named pipe, make sure we don't ask for
+       FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
+       access right! */
+    if (!(FileObject->Flags & FO_NAMED_PIPE))
+        DesiredAccess |= FILE_APPEND_DATA;
+    if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess,
+                                  DesiredAccess))
     {
-        DPRINT1("Invalid access rights\n");
         ObDereferenceObject(FileObject);
         return STATUS_ACCESS_DENIED;
     }
 
     /* Check if we got write Access */
-    if (HandleInformation.GrantedAccess & FILE_WRITE_DATA)
+    if (ObjectHandleInfo.GrantedAccess & FILE_WRITE_DATA)
     {
         /* Check the Byte Offset */
-        if (!ByteOffset ||
-            (ByteOffset->u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
-             ByteOffset->u.HighPart == -1))
+        if (ByteOffset == NULL ||
+            (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
+             CapturedByteOffset.u.HighPart == -1))
         {
             /* a valid ByteOffset is required if asynch. op. */
             if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
@@ -3496,10 +3775,11 @@ NtWriteFile (IN HANDLE FileHandle,
             }
 
             /* Use the Current Byte OFfset */
-            ByteOffset = &FileObject->CurrentByteOffset;
+            CapturedByteOffset = FileObject->CurrentByteOffset;
         }
     }
-    else if (HandleInformation.GrantedAccess & FILE_APPEND_DATA)
+    else if ((ObjectHandleInfo.GrantedAccess & FILE_APPEND_DATA) &&
+             !(FileObject->Flags & FO_NAMED_PIPE))
     {
         /* a valid ByteOffset is required if asynch. op. */
         if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
@@ -3510,8 +3790,8 @@ NtWriteFile (IN HANDLE FileHandle,
         }
 
         /* Give the drivers somethign to understand */
-        ByteOffset->u.LowPart = FILE_WRITE_TO_END_OF_FILE;
-        ByteOffset->u.HighPart = 0xffffffff;
+        CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
+        CapturedByteOffset.u.HighPart = 0xffffffff;
     }
 
     /* Check if we got an event */
@@ -3560,7 +3840,7 @@ NtWriteFile (IN HANDLE FileHandle,
                                            DeviceObject,
                                            Buffer,
                                            Length,
-                                           ByteOffset,
+                                           &CapturedByteOffset,
                                            EventObject,
                                            IoStatusBlock);
         if (Irp == NULL)
@@ -3601,7 +3881,7 @@ NtWriteFile (IN HANDLE FileHandle,
     /* Setup Stack Data */
     StackPtr = IoGetNextIrpStackLocation(Irp);
     StackPtr->FileObject = FileObject;
-    StackPtr->Parameters.Write.Key = Key ? *Key : 0;
+    StackPtr->Parameters.Write.Key = CapturedKey;
     if (FileObject->Flags & FO_WRITE_THROUGH) StackPtr->Flags = SL_WRITE_THROUGH;
 
     /* Call the Driver */