[NTOSKRNL] Use cache aligned buffer for devioctrl
[reactos.git] / ntoskrnl / io / iomgr / iofunc.c
index f1f56d0..bde78e4 100644 (file)
@@ -1,11 +1,12 @@
 /*
  * PROJECT:         ReactOS Kernel
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/io/iofunc.c
+ * FILE:            ntoskrnl/io/iomgr/iofunc.c
  * PURPOSE:         Generic I/O Functions that build IRPs for various operations
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Gunnar Dalsnes
  *                  Filip Navara (navaraf@reactos.org)
+ *                  Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
 VOID
 NTAPI
 IopCleanupAfterException(IN PFILE_OBJECT FileObject,
-                         IN PIRP Irp,
+                         IN PIRP Irp OPTIONAL,
                          IN PKEVENT Event OPTIONAL,
                          IN PKEVENT LocalEvent OPTIONAL)
 {
     PAGED_CODE();
     IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
 
-    /* Check if we had a buffer */
-    if (Irp->AssociatedIrp.SystemBuffer)
+    if (Irp)
     {
-        /* Free it */
-        ExFreePool(Irp->AssociatedIrp.SystemBuffer);
-    }
+        /* Check if we had a buffer */
+        if (Irp->AssociatedIrp.SystemBuffer)
+        {
+            /* Free it */
+            ExFreePool(Irp->AssociatedIrp.SystemBuffer);
+        }
 
-    /* Free the mdl */
-    if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
+        /* Free the mdl */
+        if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
 
-    /* Free the IRP */
-    IoFreeIrp(Irp);
+        /* Free the IRP */
+        IoFreeIrp(Irp);
+    }
 
     /* Check if we had a file lock */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
@@ -209,6 +213,10 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
     ACCESS_MASK DesiredAccess;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     ULONG BufferLength;
+    POOL_TYPE PoolType;
+
+    PAGED_CODE();
+
     IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
             DeviceHandle, IoControlCode, IsDevIoCtl);
 
@@ -341,12 +349,119 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
         DeviceObject = IoGetRelatedDeviceObject(FileObject);
     }
 
+    /* If this is a device I/O, try to do it with FastIO path */
+    if (IsDevIoCtl)
+    {
+        PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+        /* Check whether FSD is FastIO aware and provide an appropriate routine */
+        if (FastIoDispatch != NULL && FastIoDispatch->FastIoDeviceControl != NULL)
+        {
+            IO_STATUS_BLOCK KernelIosb;
+
+            /* If we have an output buffer coming from usermode */
+            if (PreviousMode != KernelMode && OutputBuffer != NULL)
+            {
+                /* Probe it according to its usage */
+                _SEH2_TRY
+                {
+                    if (AccessType == METHOD_IN_DIRECT)
+                    {
+                        ProbeForRead(OutputBuffer, OutputBufferLength, sizeof(CHAR));
+                    }
+                    else if (AccessType == METHOD_OUT_DIRECT)
+                    {
+                        ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(CHAR));
+                    }
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    /* Cleanup after exception and return */
+                    IopCleanupAfterException(FileObject, NULL, EventObject, NULL);
+
+                    /* Return the exception code */
+                    _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                }
+                _SEH2_END;
+            }
+
+            /* If we are dismounting a volume, increase the dismount count */
+            if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
+            {
+                InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
+            }
+
+            /* Call the FSD */
+            if (FastIoDispatch->FastIoDeviceControl(FileObject,
+                                                    TRUE,
+                                                    InputBuffer,
+                                                    InputBufferLength,
+                                                    OutputBuffer,
+                                                    OutputBufferLength,
+                                                    IoControlCode,
+                                                    &KernelIosb,
+                                                    DeviceObject))
+            {
+                IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
+
+                /* Write the IOSB back */
+                _SEH2_TRY
+                {
+                    *IoStatusBlock = KernelIosb;
+
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    KernelIosb.Status = _SEH2_GetExceptionCode();
+                }
+                _SEH2_END;
+
+                /* Backup our complete context in case it exists */
+                if (FileObject->CompletionContext)
+                {
+                    CompletionInfo = *(FileObject->CompletionContext);
+                }
+
+                /* If we had an event, signal it */
+                if (Event)
+                {
+                    KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
+                    ObDereferenceObject(EventObject);
+                }
+
+                /* If FO was locked, unlock it */
+                if (LockedForSynch)
+                {
+                    IopUnlockFileObject(FileObject);
+                }
+
+                /* Set completion if required */
+                if (CompletionInfo.Port != NULL && UserApcContext != NULL)
+                {
+                    if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
+                                                      CompletionInfo.Key,
+                                                      UserApcContext,
+                                                      KernelIosb.Status,
+                                                      KernelIosb.Information,
+                                                      TRUE)))
+                    {
+                        KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
+                    }
+                }
+
+                /* We're done with FastIO! */
+                ObDereferenceObject(FileObject);
+                return KernelIosb.Status;
+            }
+        }
+    }
+
     /* Clear the event */
     KeClearEvent(&FileObject->Event);
 
     /* Allocate IRP */
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
+    if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
 
     /* Setup the IRP */
     Irp->UserIosb = IoStatusBlock;
@@ -381,6 +496,8 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
     StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
         OutputBufferLength;
 
+    PoolType = IsDevIoCtl ? NonPagedPoolCacheAligned : NonPagedPool;
+
     /* Handle the Methods */
     switch (AccessType)
     {
@@ -399,7 +516,7 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
                 {
                     /* Allocate the System Buffer */
                     Irp->AssociatedIrp.SystemBuffer =
-                        ExAllocatePoolWithTag(NonPagedPool,
+                        ExAllocatePoolWithTag(PoolType,
                                               BufferLength,
                                               TAG_SYS_BUF);
 
@@ -446,7 +563,7 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
                 {
                     /* Allocate the System Buffer */
                     Irp->AssociatedIrp.SystemBuffer =
-                        ExAllocatePoolWithTag(NonPagedPool,
+                        ExAllocatePoolWithTag(PoolType,
                                               InputBufferLength,
                                               TAG_SYS_BUF);
 
@@ -498,7 +615,16 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
     }
 
     /* Use deferred completion for FS I/O */
-    Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
+    if (!IsDevIoCtl)
+    {
+        Irp->Flags |= IRP_DEFER_IO_COMPLETION;
+    }
+
+    /* If we are dismounting a volume, increaase the dismount count */
+    if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
+    {
+        InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
+    }
 
     /* Perform the call */
     return IopPerformSynchronousRequest(DeviceObject,
@@ -596,7 +722,7 @@ IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
     /* Check if this was synch I/O */
     if (!LocalEvent)
     {
-        /* Check if the requet is pending */
+        /* Check if the request is pending */
         if (Status == STATUS_PENDING)
         {
             /* Wait on the file object */
@@ -635,6 +761,265 @@ IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
     return Status;
 }
 
+NTSTATUS
+NTAPI
+IopGetFileInformation(IN PFILE_OBJECT FileObject,
+                      IN ULONG Length,
+                      IN FILE_INFORMATION_CLASS FileInfoClass,
+                      OUT PVOID Buffer,
+                      OUT PULONG ReturnedLength)
+{
+    PIRP Irp;
+    KEVENT Event;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION Stack;
+    PDEVICE_OBJECT DeviceObject;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    PAGED_CODE();
+
+    /* Allocate an IRP */
+    ObReferenceObject(FileObject);
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+    if (Irp == NULL)
+    {
+        ObDereferenceObject(FileObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Init event */
+    KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+    /* Setup the IRP */
+    Irp->UserIosb = &IoStatusBlock;
+    Irp->UserEvent = &Event;
+    Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
+    Irp->RequestorMode = KernelMode;
+    Irp->AssociatedIrp.SystemBuffer = Buffer;
+    Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME;
+    Irp->Tail.Overlay.OriginalFileObject = FileObject;
+    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+
+    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
+    Stack->FileObject = FileObject;
+    Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
+    Stack->Parameters.QueryFile.Length = Length;
+
+
+    /* Queue the IRP */
+    IopQueueIrpToThread(Irp);
+
+    /* Call the driver */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
+    }
+
+    *ReturnedLength = IoStatusBlock.Information;
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+IopGetBasicInformationFile(IN PFILE_OBJECT FileObject,
+                           OUT PFILE_BASIC_INFORMATION BasicInfo)
+{
+    ULONG ReturnedLength;
+    PDEVICE_OBJECT DeviceObject;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    PAGED_CODE();
+
+    /* Try to do it the fast way if possible */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
+        DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
+        DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
+                                                                         ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
+                                                                         BasicInfo,
+                                                                         &IoStatusBlock,
+                                                                         DeviceObject))
+    {
+        return IoStatusBlock.Status;
+    }
+
+    /* In case it failed, fall back to IRP-based method */
+    return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength);
+}
+
+NTSTATUS
+NTAPI
+IopOpenLinkOrRenameTarget(OUT PHANDLE Handle,
+                          IN PIRP Irp,
+                          IN PFILE_RENAME_INFORMATION RenameInfo,
+                          IN PFILE_OBJECT FileObject)
+{
+    NTSTATUS Status;
+    HANDLE TargetHandle;
+    UNICODE_STRING FileName;
+    PIO_STACK_LOCATION Stack;
+    PFILE_OBJECT TargetFileObject;
+    IO_STATUS_BLOCK IoStatusBlock;
+    FILE_BASIC_INFORMATION BasicInfo;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    OBJECT_HANDLE_INFORMATION HandleInformation;
+    ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
+
+    PAGED_CODE();
+
+    /* First, establish whether our target is a directory */
+    if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
+    {
+        Status = IopGetBasicInformationFile(FileObject, &BasicInfo);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
+        if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+            DesiredAccess = FILE_ADD_SUBDIRECTORY;
+        }
+    }
+
+    /* Setup the string to the target */
+    FileName.Buffer = RenameInfo->FileName;
+    FileName.Length = RenameInfo->FileNameLength;
+    FileName.MaximumLength = RenameInfo->FileNameLength;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &FileName,
+                               (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE,
+                               RenameInfo->RootDirectory,
+                               NULL);
+
+    /* And open its parent directory */
+    if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
+    {
+        ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
+#if 0
+        /* Commented out - we don't support FO extension yet
+         * FIXME: Corrected last arg when it's supported
+         */
+        Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
+                                                     DesiredAccess | SYNCHRONIZE,
+                                                     &ObjectAttributes,
+                                                     &IoStatusBlock,
+                                                     NULL,
+                                                     0,
+                                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                                     FILE_OPEN,
+                                                     FILE_OPEN_FOR_BACKUP_INTENT,
+                                                     NULL,
+                                                     0,
+                                                     CreateFileTypeNone,
+                                                     NULL,
+                                                     IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
+                                                     FileObject->DeviceObject);
+#else
+        ASSERT(FALSE);
+        UNIMPLEMENTED;
+        return STATUS_NOT_IMPLEMENTED;
+#endif
+    }
+    else
+    {
+        Status = IoCreateFile(&TargetHandle,
+                              DesiredAccess | SYNCHRONIZE,
+                              &ObjectAttributes,
+                              &IoStatusBlock,
+                              NULL,
+                              0,
+                              FILE_SHARE_READ | FILE_SHARE_WRITE,
+                              FILE_OPEN,
+                              FILE_OPEN_FOR_BACKUP_INTENT,
+                              NULL,
+                              0,
+                              CreateFileTypeNone,
+                              NULL,
+                              IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Once open, continue only if:
+     * Target exists and we're allowed to overwrite it
+     */
+    Stack = IoGetNextIrpStackLocation(Irp);
+    if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
+        !RenameInfo->ReplaceIfExists &&
+        IoStatusBlock.Information == FILE_EXISTS)
+    {
+        ObCloseHandle(TargetHandle, KernelMode);
+        return STATUS_OBJECT_NAME_COLLISION;
+    }
+
+    /* Now, we'll get the associated device of the target, to check for same device location
+     * So, get the FO first
+     */
+    Status = ObReferenceObjectByHandle(TargetHandle,
+                                       FILE_WRITE_DATA,
+                                       IoFileObjectType,
+                                       KernelMode,
+                                       (PVOID *)&TargetFileObject,
+                                       &HandleInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        ObCloseHandle(TargetHandle, KernelMode);
+        return Status;
+    }
+
+    /* We can dereference, we have the handle */
+    ObDereferenceObject(TargetFileObject);
+    /* If we're not on the same device, error out **/
+    if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
+    {
+        ObCloseHandle(TargetHandle, KernelMode);
+        return STATUS_NOT_SAME_DEVICE;
+    }
+
+    /* Return parent directory file object and handle */
+    Stack->Parameters.SetFile.FileObject = TargetFileObject;
+    *Handle = TargetHandle;
+
+    return STATUS_SUCCESS;
+}
+
+static
+ULONG
+IopGetFileMode(IN PFILE_OBJECT FileObject)
+{
+    ULONG Mode = 0;
+
+    if (FileObject->Flags & FO_WRITE_THROUGH)
+        Mode |= FILE_WRITE_THROUGH;
+
+    if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
+        Mode |= FILE_SEQUENTIAL_ONLY;
+
+    if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
+        Mode |= FILE_NO_INTERMEDIATE_BUFFERING;
+
+    if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+    {
+        if (FileObject->Flags & FO_ALERTABLE_IO)
+            Mode |= FILE_SYNCHRONOUS_IO_ALERT;
+        else
+            Mode |= FILE_SYNCHRONOUS_IO_NONALERT;
+    }
+
+    if (FileObject->Flags & FO_DELETE_ON_CLOSE)
+        Mode |= FILE_DELETE_ON_CLOSE;
+
+    return Mode;
+}
+
 /* PUBLIC FUNCTIONS **********************************************************/
 
 /*
@@ -850,7 +1235,7 @@ IoSetInformation(IN PFILE_OBJECT FileObject,
     /* Check if this was synch I/O */
     if (!LocalEvent)
     {
-        /* Check if the requet is pending */
+        /* Check if the request is pending */
         if (Status == STATUS_PENDING)
         {
             /* Wait on the file object */
@@ -1232,6 +1617,7 @@ NtLockFile(IN HANDLE FileHandle,
     LARGE_INTEGER CapturedByteOffset, CapturedLength;
     NTSTATUS Status;
     OBJECT_HANDLE_INFORMATION HandleInformation;
+    PFAST_IO_DISPATCH FastIoDispatch;
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     CapturedLength.QuadPart = 0;
@@ -1299,6 +1685,62 @@ NtLockFile(IN HANDLE FileHandle,
     /* Get the device object */
     DeviceObject = IoGetRelatedDeviceObject(FileObject);
 
+    /* Try to do it the FastIO way if possible */
+    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+    if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
+    {
+        IO_STATUS_BLOCK KernelIosb;
+
+        if (FastIoDispatch->FastIoLock(FileObject,
+                                       &CapturedByteOffset,
+                                       &CapturedLength,
+                                       PsGetCurrentProcess(),
+                                       Key,
+                                       FailImmediately,
+                                       ExclusiveLock,
+                                       &KernelIosb,
+                                       DeviceObject))
+        {
+            /* Write the IOSB back */
+            _SEH2_TRY
+            {
+                *IoStatusBlock = KernelIosb;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                KernelIosb.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* If we had an event, signal it */
+            if (EventHandle)
+            {
+                KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+                ObDereferenceObject(Event);
+            }
+
+            /* Set completion if required */
+            if (FileObject->CompletionContext != NULL && ApcContext != NULL)
+            {
+                if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
+                                                  FileObject->CompletionContext->Key,
+                                                  ApcContext,
+                                                  KernelIosb.Status,
+                                                  KernelIosb.Information,
+                                                  TRUE)))
+                {
+                    KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
+                }
+            }
+
+            FileObject->LockOperation = TRUE;
+
+            /* We're done with FastIO! */
+            ObDereferenceObject(FileObject);
+            return KernelIosb.Status;
+        }
+    }
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
@@ -1462,6 +1904,14 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
         return Status;
     }
 
+    /* Are there two associated completion routines? */
+    if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
+    {
+        ObDereferenceObject(FileObject);
+        if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
+        return STATUS_INVALID_PARAMETER;
+    }
+
     /* Check if we have an even handle */
     if (EventHandle)
     {
@@ -1475,6 +1925,7 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
         if (!NT_SUCCESS(Status))
         {
             /* Fail */
+            if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
             ObDereferenceObject(FileObject);
             return Status;
         }
@@ -1633,6 +2084,12 @@ NtQueryInformationFile(IN HANDLE FileHandle,
     PVOID NormalContext;
     KIRQL OldIrql;
     IO_STATUS_BLOCK KernelIosb;
+    BOOLEAN CallDriver = TRUE;
+    PFILE_ACCESS_INFORMATION AccessBuffer;
+    PFILE_MODE_INFORMATION ModeBuffer;
+    PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
+    PFILE_ALL_INFORMATION AllBuffer;
+    PFAST_IO_DISPATCH FastIoDispatch;
     PAGED_CODE();
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
 
@@ -1670,6 +2127,7 @@ NtQueryInformationFile(IN HANDLE FileHandle,
         }
         _SEH2_END;
     }
+#if DBG
     else
     {
         /* Validate the information class */
@@ -1687,6 +2145,7 @@ NtQueryInformationFile(IN HANDLE FileHandle,
             return STATUS_INFO_LENGTH_MISMATCH;
         }
     }
+#endif
 
     /* Reference the Handle */
     Status = ObReferenceObjectByHandle(FileHandle,
@@ -1756,6 +2215,61 @@ NtQueryInformationFile(IN HANDLE FileHandle,
         LocalEvent = TRUE;
     }
 
+    /* Check if FastIO is possible for the two available information classes */
+    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+    if (FastIoDispatch != NULL &&
+        ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
+         (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
+    {
+        BOOLEAN Success = FALSE;
+
+        if (FileInformationClass == FileBasicInformation)
+        {
+            Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
+                                                           FileInformation,
+                                                           &KernelIosb,
+                                                           DeviceObject);
+        }
+        else
+        {
+            Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
+                                                              FileInformation,
+                                                              &KernelIosb,
+                                                              DeviceObject);
+        }
+
+        /* If call succeed */
+        if (Success)
+        {
+            /* Write the IOSB back */
+            _SEH2_TRY
+            {
+                *IoStatusBlock = KernelIosb;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                KernelIosb.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Free the event if we had one */
+            if (LocalEvent)
+            {
+                ExFreePoolWithTag(Event, TAG_IO);
+            }
+
+            /* If FO was locked, unlock it */
+            if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+            {
+                IopUnlockFileObject(FileObject);
+            }
+
+            /* We're done with FastIO! */
+            ObDereferenceObject(FileObject);
+            return KernelIosb.Status;
+        }
+    }
+
     /* Clear the File Object event */
     KeClearEvent(&FileObject->Event);
 
@@ -1813,8 +2327,51 @@ NtQueryInformationFile(IN HANDLE FileHandle,
     /* Update operation counts */
     IopUpdateOperationCount(IopOtherTransfer);
 
+    /* Fill in file information before calling the driver.
+       See 'File System Internals' page 485.*/
+    if (FileInformationClass == FileAccessInformation)
+    {
+        AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
+        AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
+        Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
+        CallDriver = FALSE;
+    }
+    else if (FileInformationClass == FileModeInformation)
+    {
+        ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
+        ModeBuffer->Mode = IopGetFileMode(FileObject);
+        Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
+        CallDriver = FALSE;
+    }
+    else if (FileInformationClass == FileAlignmentInformation)
+    {
+        AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
+        AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
+        Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
+        CallDriver = FALSE;
+    }
+    else if (FileInformationClass == FileAllInformation)
+    {
+        AllBuffer = Irp->AssociatedIrp.SystemBuffer;
+        AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
+        AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
+        AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
+        Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
+                                    sizeof(FILE_MODE_INFORMATION) +
+                                    sizeof(FILE_ALIGNMENT_INFORMATION);
+    }
+
     /* Call the Driver */
-    Status = IoCallDriver(DeviceObject, Irp);
+    if (CallDriver)
+    {
+        Status = IoCallDriver(DeviceObject, Irp);
+    }
+    else
+    {
+        Status = STATUS_SUCCESS;
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+    }
+
     if (Status == STATUS_PENDING)
     {
         /* Check if this was async I/O */
@@ -1948,6 +2505,10 @@ NtReadFile(IN HANDLE FileHandle,
     ULONG CapturedKey = 0;
     BOOLEAN Synchronous = FALSE;
     PMDL Mdl;
+    PFAST_IO_DISPATCH FastIoDispatch;
+    IO_STATUS_BLOCK KernelIosb;
+    BOOLEAN Success;
+
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
@@ -2017,13 +2578,16 @@ NtReadFile(IN HANDLE FileHandle,
         KeClearEvent(EventObject);
     }
 
+    /* Get the device object */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
         /* Lock the file object */
         IopLockFileObject(FileObject);
 
-        /* Check if we don't have a byte offset avilable */
+        /* Check if we don't have a byte offset available */
         if (!(ByteOffset) ||
             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
              (CapturedByteOffset.u.HighPart == -1)))
@@ -2032,6 +2596,63 @@ NtReadFile(IN HANDLE FileHandle,
             CapturedByteOffset = FileObject->CurrentByteOffset;
         }
 
+        /* If the file is cached, try fast I/O */
+        if (FileObject->PrivateCacheMap)
+        {
+            /* Perform fast read */
+            FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+            ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
+
+            Success = FastIoDispatch->FastIoRead(FileObject,
+                                                 &CapturedByteOffset,
+                                                 Length,
+                                                 TRUE,
+                                                 CapturedKey,
+                                                 Buffer,
+                                                 &KernelIosb,
+                                                 DeviceObject);
+
+            /* Only accept the result if we got a straightforward status */
+            if (Success &&
+                (KernelIosb.Status == STATUS_SUCCESS ||
+                 KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
+                 KernelIosb.Status == STATUS_END_OF_FILE))
+            {
+                /* Fast path -- update transfer & operation counts */
+                IopUpdateOperationCount(IopReadTransfer);
+                IopUpdateTransferCount(IopReadTransfer,
+                                       (ULONG)KernelIosb.Information);
+
+                /* Enter SEH to write the IOSB back */
+                _SEH2_TRY
+                {
+                    /* Write it back to the caller */
+                    *IoStatusBlock = KernelIosb;
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    /* The caller's IOSB was invalid, so fail */
+                    if (EventObject) ObDereferenceObject(EventObject);
+                    IopUnlockFileObject(FileObject);
+                    ObDereferenceObject(FileObject);
+                    _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                }
+                _SEH2_END;
+
+                /* Signal the completion event */
+                if (EventObject)
+                {
+                    KeSetEvent(EventObject, 0, FALSE);
+                    ObDereferenceObject(EventObject);
+                }
+
+                /* Clean up */
+                IopUnlockFileObject(FileObject);
+                ObDereferenceObject(FileObject);
+                return KernelIosb.Status;
+            }
+        }
+
         /* Remember we are sync */
         Synchronous = TRUE;
     }
@@ -2044,15 +2665,12 @@ NtReadFile(IN HANDLE FileHandle,
         return STATUS_INVALID_PARAMETER;
     }
 
-    /* Get the device object */
-    DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
     /* Clear the File Object's event */
     KeClearEvent(&FileObject->Event);
 
     /* Allocate the IRP */
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+    if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
 
     /* Set the IRP */
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
@@ -2120,6 +2738,8 @@ NtReadFile(IN HANDLE FileHandle,
             {
                 /* Allocate an MDL */
                 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
+                if (!Mdl)
+                    ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
                 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
             }
             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -2218,6 +2838,8 @@ NtSetInformationFile(IN HANDLE FileHandle,
     PVOID Queue;
     PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
     PIO_COMPLETION_CONTEXT Context;
+    PFILE_RENAME_INFORMATION RenameInfo;
+    HANDLE TargetHandle = NULL;
     PAGED_CODE();
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
 
@@ -2298,6 +2920,9 @@ NtSetInformationFile(IN HANDLE FileHandle,
         DeviceObject = IoGetRelatedDeviceObject(FileObject);
     }
 
+    DPRINT("Will call: %p\n", DeviceObject);
+    DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
+
     /* Check if this is a file that was opened for Synch I/O */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
@@ -2469,6 +3094,58 @@ NtSetInformationFile(IN HANDLE FileHandle,
         Irp->IoStatus.Status = Status;
         Irp->IoStatus.Information = 0;
     }
+    else if (FileInformationClass == FileRenameInformation ||
+             FileInformationClass == FileLinkInformation ||
+             FileInformationClass == FileMoveClusterInformation)
+    {
+        /* Get associated information */
+        RenameInfo = Irp->AssociatedIrp.SystemBuffer;
+
+        /* Only rename if:
+         * -> We have a name
+         * -> In unicode
+         * -> sizes are valid
+         */
+        if (RenameInfo->FileNameLength != 0 &&
+            !(RenameInfo->FileNameLength & 1) &&
+            (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
+        {
+            /* Properly set information received */
+            if (FileInformationClass == FileMoveClusterInformation)
+            {
+                StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
+            }
+            else
+            {
+                StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
+            }
+
+            /* If we got fully path OR relative target, attempt a parent directory open */
+            if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
+            {
+                Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
+                if (!NT_SUCCESS(Status))
+                {
+                    Irp->IoStatus.Status = Status;
+                }
+                else
+                {
+                    /* Call the Driver */
+                    Status = IoCallDriver(DeviceObject, Irp);
+                }
+            }
+            else
+            {
+                /* Call the Driver */
+                Status = IoCallDriver(DeviceObject, Irp);
+            }
+        }
+        else
+        {
+            Status = STATUS_INVALID_PARAMETER;
+            Irp->IoStatus.Status = Status;
+        }
+    }
     else
     {
         /* Call the Driver */
@@ -2560,6 +3237,11 @@ NtSetInformationFile(IN HANDLE FileHandle,
         if (!LocalEvent) IopUnlockFileObject(FileObject);
     }
 
+    if (TargetHandle != NULL)
+    {
+        ObCloseHandle(TargetHandle, KernelMode);
+    }
+
     /* Return the Status */
     return Status;
 }
@@ -2601,6 +3283,7 @@ NtUnlockFile(IN HANDLE FileHandle,
     NTSTATUS Status;
     OBJECT_HANDLE_INFORMATION HandleInformation;
     IO_STATUS_BLOCK KernelIosb;
+    PFAST_IO_DISPATCH FastIoDispatch;
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     CapturedLength.QuadPart = 0;
@@ -2661,6 +3344,35 @@ NtUnlockFile(IN HANDLE FileHandle,
         DeviceObject = IoGetRelatedDeviceObject(FileObject);
     }
 
+    /* Try to do it the FastIO way if possible */
+    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+    if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
+    {
+        if (FastIoDispatch->FastIoUnlockSingle(FileObject,
+                                               &CapturedByteOffset,
+                                               &CapturedLength,
+                                               PsGetCurrentProcess(),
+                                               Key,
+                                               &KernelIosb,
+                                               DeviceObject))
+        {
+            /* Write the IOSB back */
+            _SEH2_TRY
+            {
+                *IoStatusBlock = KernelIosb;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                KernelIosb.Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* We're done with FastIO! */
+            ObDereferenceObject(FileObject);
+            return KernelIosb.Status;
+        }
+    }
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
@@ -2782,17 +3494,19 @@ NtWriteFile(IN HANDLE FileHandle,
     BOOLEAN Synchronous = FALSE;
     PMDL Mdl;
     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
+    PFAST_IO_DISPATCH FastIoDispatch;
+    IO_STATUS_BLOCK KernelIosb;
+    BOOLEAN Success;
+
     PAGED_CODE();
     CapturedByteOffset.QuadPart = 0;
     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
 
-    /* Get File Object */
-    Status = ObReferenceObjectByHandle(FileHandle,
-                                       0,
-                                       IoFileObjectType,
-                                       PreviousMode,
-                                       (PVOID*)&FileObject,
-                                       &ObjectHandleInfo);
+    /* Get File Object for write */
+    Status = ObReferenceFileObjectForWrite(FileHandle,
+                                           PreviousMode,
+                                           &FileObject,
+                                           &ObjectHandleInfo);
     if (!NT_SUCCESS(Status)) return Status;
 
     /* Validate User-Mode Buffers */
@@ -2800,21 +3514,6 @@ NtWriteFile(IN HANDLE FileHandle,
     {
         _SEH2_TRY
         {
-            /*
-             * Check if the handle has either FILE_WRITE_DATA or
-             * FILE_APPEND_DATA 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 (!(ObjectHandleInfo.GrantedAccess &
-                 ((!(FileObject->Flags & FO_NAMED_PIPE) ?
-                   FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
-            {
-                /* We failed */
-                ObDereferenceObject(FileObject);
-                _SEH2_YIELD(return STATUS_ACCESS_DENIED);
-            }
-
             /* Probe the status block */
             ProbeForWriteIoStatusBlock(IoStatusBlock);
 
@@ -2833,7 +3532,8 @@ NtWriteFile(IN HANDLE FileHandle,
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Return the exception code */
+            /* Release the file object and return the exception code */
+            ObDereferenceObject(FileObject);
             _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
         _SEH2_END;
@@ -2875,13 +3575,16 @@ NtWriteFile(IN HANDLE FileHandle,
         KeClearEvent(EventObject);
     }
 
+    /* Get the device object */
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
     /* Check if we should use Sync IO or not */
     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
     {
         /* Lock the file object */
         IopLockFileObject(FileObject);
 
-        /* Check if we don't have a byte offset avilable */
+        /* Check if we don't have a byte offset available */
         if (!(ByteOffset) ||
             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
              (CapturedByteOffset.u.HighPart == -1)))
@@ -2890,6 +3593,61 @@ NtWriteFile(IN HANDLE FileHandle,
             CapturedByteOffset = FileObject->CurrentByteOffset;
         }
 
+        /* If the file is cached, try fast I/O */
+        if (FileObject->PrivateCacheMap)
+        {
+            /* Perform fast write */
+            FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+            ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
+
+            Success = FastIoDispatch->FastIoWrite(FileObject,
+                                                  &CapturedByteOffset,
+                                                  Length,
+                                                  TRUE,
+                                                  CapturedKey,
+                                                  Buffer,
+                                                  &KernelIosb,
+                                                  DeviceObject);
+
+            /* Only accept the result if it was successful */
+            if (Success &&
+                KernelIosb.Status == STATUS_SUCCESS)
+            {
+                /* Fast path -- update transfer & operation counts */
+                IopUpdateOperationCount(IopWriteTransfer);
+                IopUpdateTransferCount(IopWriteTransfer,
+                                       (ULONG)KernelIosb.Information);
+
+                /* Enter SEH to write the IOSB back */
+                _SEH2_TRY
+                {
+                    /* Write it back to the caller */
+                    *IoStatusBlock = KernelIosb;
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    /* The caller's IOSB was invalid, so fail */
+                    if (EventObject) ObDereferenceObject(EventObject);
+                    IopUnlockFileObject(FileObject);
+                    ObDereferenceObject(FileObject);
+                    _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                }
+                _SEH2_END;
+
+                /* Signal the completion event */
+                if (EventObject)
+                {
+                    KeSetEvent(EventObject, 0, FALSE);
+                    ObDereferenceObject(EventObject);
+                }
+
+                /* Clean up */
+                IopUnlockFileObject(FileObject);
+                ObDereferenceObject(FileObject);
+                return KernelIosb.Status;
+            }
+        }
+
         /* Remember we are sync */
         Synchronous = TRUE;
     }
@@ -2902,15 +3660,12 @@ NtWriteFile(IN HANDLE FileHandle,
         return STATUS_INVALID_PARAMETER;
     }
 
-    /* Get the device object */
-    DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
     /* Clear the File Object's event */
     KeClearEvent(&FileObject->Event);
 
     /* Allocate the IRP */
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+    if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
 
     /* Set the IRP */
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
@@ -2980,6 +3735,8 @@ NtWriteFile(IN HANDLE FileHandle,
             {
                 /* Allocate an MDL */
                 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
+                if (!Mdl)
+                    ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
                 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
             }
             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)