[NTOSKRNL] Fix remaining access computation on open
[reactos.git] / ntoskrnl / io / iomgr / file.c
index 8ecf99f..1768bc2 100644 (file)
@@ -1,12 +1,13 @@
 /*
  * PROJECT:         ReactOS Kernel
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/io/file.c
+ * FILE:            ntoskrnl/io/iomgr/file.c
  * PURPOSE:         Functions that deal with managing the FILE_OBJECT itself.
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Gunnar Dalsnes
  *                  Eric Kohl
  *                  Filip Navara (navaraf@reactos.org)
+ *                  Pierre Schweitzer
  */
 
 /* INCLUDES *****************************************************************/
@@ -15,6 +16,8 @@
 #define NDEBUG
 #include <debug.h>
 
+extern ERESOURCE IopSecurityResource;
+
 /* PRIVATE FUNCTIONS *********************************************************/
 
 VOID
@@ -162,6 +165,107 @@ IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
     }
 }
 
+VOID
+NTAPI
+IopDoNameTransmogrify(IN PIRP Irp,
+                      IN PFILE_OBJECT FileObject,
+                      IN PREPARSE_DATA_BUFFER DataBuffer)
+{
+    PWSTR Buffer;
+    USHORT Length;
+    USHORT RequiredLength;
+    PWSTR NewBuffer;
+
+    PAGED_CODE();
+
+    ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
+    ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
+    ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+    ASSERT(DataBuffer != NULL);
+    ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+    ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+    ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+    /* First of all, validate data */
+    if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
+        (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+         DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
+         FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
+    {
+        Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+    }
+
+    /* Everything went right */
+    if (NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        /* Compute buffer & length */
+        Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
+                                    DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
+        Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
+
+        /* Check we don't overflow */
+        if (((ULONG)MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
+        {
+            Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+        }
+        else
+        {
+            /* Compute how much mem we'll need */
+            RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
+
+            /* Check if FileObject can already hold what we need */
+            if (FileObject->FileName.MaximumLength >= RequiredLength)
+            {
+                NewBuffer = FileObject->FileName.Buffer;
+            }
+            else
+            {
+                /* Allocate otherwise */
+                NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
+                if (NewBuffer == NULL)
+                {
+                     Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+                }
+            }
+        }
+    }
+
+    /* Everything went right */
+    if (NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        /* Copy reserved */
+        if (DataBuffer->Reserved)
+        {
+            RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
+                          (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
+                          DataBuffer->Reserved);
+        }
+
+        /* Then, buffer */
+        if (Length)
+        {
+            RtlCopyMemory(NewBuffer, Buffer, Length);
+        }
+
+        /* And finally replace buffer if new one was allocated */
+        FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
+        if (NewBuffer != FileObject->FileName.Buffer)
+        {
+            if (FileObject->FileName.Buffer)
+            {
+                ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+            }
+
+            FileObject->FileName.Buffer = NewBuffer;
+            FileObject->FileName.MaximumLength = RequiredLength;
+            FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
+        }
+    }
+
+    /* We don't need them anymore - it was allocated by the driver */
+    ExFreePool(DataBuffer);
+}
+
 NTSTATUS
 NTAPI
 IopParseDevice(IN PVOID ParseObject,
@@ -182,7 +286,7 @@ IopParseDevice(IN PVOID ParseObject,
     PFILE_OBJECT FileObject;
     PVPB Vpb = NULL;
     PIRP Irp;
-    PEXTENDED_IO_STACK_LOCATION StackLoc;
+    PIO_STACK_LOCATION StackLoc;
     IO_SECURITY_CONTEXT SecurityContext;
     IO_STATUS_BLOCK IoStatusBlock;
     BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
@@ -197,103 +301,368 @@ IopParseDevice(IN PVOID ParseObject,
     BOOLEAN AccessGranted, LockHeld = FALSE;
     PPRIVILEGE_SET Privileges = NULL;
     UNICODE_STRING FileString;
+    USHORT Attempt;
     IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
             ParseObject, RemainingName);
 
-    /* Assume failure */
-    *Object = NULL;
+    for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
+    {
+        /* Assume failure */
+        *Object = NULL;
 
-    /* Validate the open packet */
-    if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
+        /* Validate the open packet */
+        if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
 
-    /* Check if we have a related file object */
-    if (OpenPacket->RelatedFileObject)
-    {
-        /* Use the related file object's device object */
-        OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
-    }
+        /* Valide reparse point in case we traversed a mountpoint */
+        if (OpenPacket->TraversedMountPoint)
+        {
+            /* This is a reparse point we understand */
+            ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
 
-    /* Validate device status */
-    Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
-    if (!NT_SUCCESS(Status))
-    {
-        /* We failed, return status */
-        OpenPacket->FinalStatus = Status;
-        return Status;
-    }
+            /* Make sure we're dealing with correct DO */
+            if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
+                OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
+                OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
+                OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
+            {
+                OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
+                return STATUS_IO_REPARSE_DATA_INVALID;
+            }
+        }
 
-    /* Map the generic mask and set the new mapping in the access state */
-    RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
-                      &IoFileObjectType->TypeInfo.GenericMapping);
-    RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
-                      &IoFileObjectType->TypeInfo.GenericMapping);
-    SeSetAccessStateGenericMapping(AccessState,
-                                   &IoFileObjectType->TypeInfo.GenericMapping);
-    DesiredAccess = AccessState->RemainingDesiredAccess;
+        /* Check if we have a related file object */
+        if (OpenPacket->RelatedFileObject)
+        {
+            /* Use the related file object's device object */
+            OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
+        }
 
-    /* Check what kind of access checks to do */
-    if ((AccessMode != KernelMode) ||
-        (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
-    {
-        /* Call is from user-mode or kernel is forcing checks */
-        CheckMode = UserMode;
-    }
-    else
-    {
-        /* Call is from the kernel */
-        CheckMode = KernelMode;
-    }
+        /* Validate device status */
+        Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
+        if (!NT_SUCCESS(Status))
+        {
+            /* We failed, return status */
+            OpenPacket->FinalStatus = Status;
+            return Status;
+        }
 
-    /* Check privilege for backup or restore operation */
-    IopCheckBackupRestorePrivilege(AccessState,
-                                   &OpenPacket->CreateOptions,
-                                   CheckMode,
-                                   OpenPacket->Disposition);
+        /* Map the generic mask and set the new mapping in the access state */
+        RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
+                          &IoFileObjectType->TypeInfo.GenericMapping);
+        RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
+                          &IoFileObjectType->TypeInfo.GenericMapping);
+        SeSetAccessStateGenericMapping(AccessState,
+                                       &IoFileObjectType->TypeInfo.GenericMapping);
+        DesiredAccess = AccessState->RemainingDesiredAccess;
 
-    /* Check if we are re-parsing */
-    if (((OpenPacket->Override) && !(RemainingName->Length)) ||
-        (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
-    {
-        /* Get granted access from the last call */
-        DesiredAccess |= AccessState->PreviouslyGrantedAccess;
-    }
+        /* Check what kind of access checks to do */
+        if ((AccessMode != KernelMode) ||
+            (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
+        {
+            /* Call is from user-mode or kernel is forcing checks */
+            CheckMode = UserMode;
+        }
+        else
+        {
+            /* Call is from the kernel */
+            CheckMode = KernelMode;
+        }
 
-    /* Check if this is a volume open */
-    if ((OpenPacket->RelatedFileObject) &&
-        (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
-        !(RemainingName->Length))
-    {
-        /* It is */
-        VolumeOpen = TRUE;
-    }
+        /* Check privilege for backup or restore operation */
+        IopCheckBackupRestorePrivilege(AccessState,
+                                       &OpenPacket->CreateOptions,
+                                       CheckMode,
+                                       OpenPacket->Disposition);
 
-    /* Now check if we need access checks */
-    if (((AccessMode != KernelMode) ||
-         (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
-        (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
-        !(OpenPacket->Override))
-    {
-        /* Check if a device object is being parsed  */
-        if (!RemainingName->Length)
+        /* Check if we are re-parsing */
+        if (((OpenPacket->Override) && !(RemainingName->Length)) ||
+            (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
+        {
+            /* Get granted access from the last call */
+            DesiredAccess |= AccessState->PreviouslyGrantedAccess;
+        }
+
+        /* Check if this is a volume open */
+        if ((OpenPacket->RelatedFileObject) &&
+            (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
+            !(RemainingName->Length))
+        {
+            /* It is */
+            VolumeOpen = TRUE;
+        }
+
+        /* Now check if we need access checks */
+        if (((AccessMode != KernelMode) ||
+             (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
+            (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
+            !(OpenPacket->Override))
         {
+            KeEnterCriticalRegion();
+            ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
+
+            /* Check if a device object is being parsed  */
+            if (!RemainingName->Length)
+            {
+                /* Lock the subject context */
+                SeLockSubjectContext(&AccessState->SubjectSecurityContext);
+                LockHeld = TRUE;
+
+                /* Do access check */
+                AccessGranted = SeAccessCheck(OriginalDeviceObject->
+                                              SecurityDescriptor,
+                                              &AccessState->SubjectSecurityContext,
+                                              LockHeld,
+                                              DesiredAccess,
+                                              0,
+                                              &Privileges,
+                                              &IoFileObjectType->
+                                              TypeInfo.GenericMapping,
+                                              UserMode,
+                                              &GrantedAccess,
+                                              &Status);
+                if (Privileges)
+                {
+                    /* Append and free the privileges */
+                    SeAppendPrivileges(AccessState, Privileges);
+                    SeFreePrivileges(Privileges);
+                }
+
+                /* Check if we got access */
+                if (AccessGranted)
+                {
+                    /* Update access state */
+                    AccessState->PreviouslyGrantedAccess |= GrantedAccess;
+                    AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
+                                                             MAXIMUM_ALLOWED);
+                    OpenPacket->Override= TRUE;
+                }
+
+                FileString.Length = 8;
+                FileString.MaximumLength = 8;
+                FileString.Buffer = L"File";
+
+                /* Do Audit/Alarm for open operation */
+                SeOpenObjectAuditAlarm(&FileString,
+                                       OriginalDeviceObject,
+                                       CompleteName,
+                                       OriginalDeviceObject->SecurityDescriptor,
+                                       AccessState,
+                                       FALSE,
+                                       AccessGranted,
+                                       UserMode,
+                                       &AccessState->GenerateOnClose);
+            }
+            else
+            {
+                /* Check if we need to do traverse validation */
+                if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
+                    ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
+                     (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
+                {
+                    /* Check if this is a restricted token */
+                    if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
+                    {
+                        /* Do the FAST traverse check */
+                        AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
+                                                            AccessState,
+                                                            FILE_TRAVERSE,
+                                                            UserMode);
+                    }
+                    else
+                    {
+                        /* Fail */
+                        AccessGranted = FALSE;
+                    }
+
+                    /* Check if we failed to get access */
+                    if (!AccessGranted)
+                    {
+                        /* Lock the subject context */
+                        SeLockSubjectContext(&AccessState->SubjectSecurityContext);
+                        LockHeld = TRUE;
+
+                        /* Do access check */
+                        AccessGranted = SeAccessCheck(OriginalDeviceObject->
+                                                      SecurityDescriptor,
+                                                      &AccessState->SubjectSecurityContext,
+                                                      LockHeld,
+                                                      FILE_TRAVERSE,
+                                                      0,
+                                                      &Privileges,
+                                                      &IoFileObjectType->
+                                                      TypeInfo.GenericMapping,
+                                                      UserMode,
+                                                      &GrantedAccess,
+                                                      &Status);
+                        if (Privileges)
+                        {
+                            /* Append and free the privileges */
+                            SeAppendPrivileges(AccessState, Privileges);
+                            SeFreePrivileges(Privileges);
+                        }
+                    }
+
+                    /* FIXME: Do Audit/Alarm for traverse check */
+                }
+                else
+                {
+                    /* Access automatically granted */
+                    AccessGranted = TRUE;
+                }
+            }
+
+            ExReleaseResourceLite(&IopSecurityResource);
+            KeLeaveCriticalRegion();
+
+            /* Check if we hold the lock */
+            if (LockHeld)
+            {
+                /* Release it */
+                SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
+            }
+
+            /* Check if access failed */
+            if (!AccessGranted)
+            {
+                /* Dereference the device and fail */
+                DPRINT1("Traverse access failed!\n");
+                IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+                return STATUS_ACCESS_DENIED;
+            }
+        }
+
+        /* Check if we can simply use a dummy file */
+        UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
+
+#if 1
+        /* FIXME: Small hack still exists, have to check why...
+         * This is triggered multiple times by usetup and then once per boot.
+         */
+        if (ExpInTextModeSetup &&
+            !(DirectOpen) &&
+            !(RemainingName->Length) &&
+            !(OpenPacket->RelatedFileObject) &&
+            ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
+            (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
+            !(UseDummyFile))
+        {
+            DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
+            DesiredAccess & ~(SYNCHRONIZE |
+                              FILE_READ_ATTRIBUTES |
+                              READ_CONTROL |
+                              ACCESS_SYSTEM_SECURITY |
+                              WRITE_OWNER |
+                              WRITE_DAC));
+            DirectOpen = TRUE;
+        }
+#endif
+
+        /* Check if this is a direct open */
+        if (!(RemainingName->Length) &&
+            !(OpenPacket->RelatedFileObject) &&
+            ((DesiredAccess & ~(SYNCHRONIZE |
+                                FILE_READ_ATTRIBUTES |
+                                READ_CONTROL |
+                                ACCESS_SYSTEM_SECURITY |
+                                WRITE_OWNER |
+                                WRITE_DAC)) == 0) &&
+            !(UseDummyFile))
+        {
+            /* Remember this for later */
+            DirectOpen = TRUE;
+        }
+
+        /* Check if we have a related FO that wasn't a direct open */
+        if ((OpenPacket->RelatedFileObject) &&
+            !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
+        {
+            /* The device object is the one we were given */
+            DeviceObject = ParseObject;
+
+            /* Check if the related FO had a VPB */
+            if (OpenPacket->RelatedFileObject->Vpb)
+            {
+                /* Yes, remember it */
+                Vpb = OpenPacket->RelatedFileObject->Vpb;
+
+                /* Reference it */
+                InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
+
+                /* Check if we were given a specific top level device to use */
+                if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
+                {
+                    DeviceObject = Vpb->DeviceObject;
+                }
+            }
+        }
+        else
+        {
+            /* Check if it has a VPB */
+            if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
+            {
+                /* Check if the VPB is mounted, and mount it */
+                Vpb = IopCheckVpbMounted(OpenPacket,
+                                         OriginalDeviceObject,
+                                         RemainingName,
+                                         &Status);
+                if (!Vpb) return Status;
+
+                /* Get the VPB's device object */
+                DeviceObject = Vpb->DeviceObject;
+            }
+            else
+            {
+                /* The device object is the one we were given */
+                DeviceObject = OriginalDeviceObject;
+            }
+
+            /* If we weren't given a specific top level device, look for an attached device */
+            if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
+                DeviceObject->AttachedDevice)
+            {
+                /* Get the attached device */
+                DeviceObject = IoGetAttachedDevice(DeviceObject);
+            }
+        }
+
+        if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
+        {
+            // FIXME: Verify our device object is good to use
+            ASSERT(DirectOpen == FALSE);
+        }
+
+        /* If we traversed a mount point, reset the information */
+        if (OpenPacket->TraversedMountPoint)
+        {
+            OpenPacket->TraversedMountPoint = FALSE;
+        }
+
+        /* Check if this is a secure FSD */
+        if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
+            ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
+            (!VolumeOpen))
+        {
+            Privileges = NULL;
+            GrantedAccess = 0;
+
+            KeEnterCriticalRegion();
+            ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
+
             /* Lock the subject context */
             SeLockSubjectContext(&AccessState->SubjectSecurityContext);
-            LockHeld = TRUE;
 
             /* Do access check */
-            AccessGranted = SeAccessCheck(OriginalDeviceObject->
-                                          SecurityDescriptor,
+            AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
                                           &AccessState->SubjectSecurityContext,
-                                          LockHeld,
+                                          TRUE,
                                           DesiredAccess,
                                           0,
                                           &Privileges,
-                                          &IoFileObjectType->
-                                          TypeInfo.GenericMapping,
+                                          &IoFileObjectType->TypeInfo.GenericMapping,
                                           UserMode,
                                           &GrantedAccess,
                                           &Status);
-            if (Privileges)
+            if (Privileges != NULL)
             {
                 /* Append and free the privileges */
                 SeAppendPrivileges(AccessState, Privileges);
@@ -301,22 +670,21 @@ IopParseDevice(IN PVOID ParseObject,
             }
 
             /* Check if we got access */
-            if (AccessGranted)
+            if (GrantedAccess)
             {
-                /* Update access state */
                 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
-                AccessState->RemainingDesiredAccess &= ~(GrantedAccess &
-                                                         MAXIMUM_ALLOWED);
-                OpenPacket->Override= TRUE;
+                AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
             }
 
             FileString.Length = 8;
             FileString.MaximumLength = 8;
             FileString.Buffer = L"File";
 
-            /* Do Audit/Alarm for open operation */
+            /* Do Audit/Alarm for open operation
+             * NOTA: we audit target device object
+             */
             SeOpenObjectAuditAlarm(&FileString,
-                                   OriginalDeviceObject,
+                                   DeviceObject,
                                    CompleteName,
                                    OriginalDeviceObject->SecurityDescriptor,
                                    AccessState,
@@ -324,490 +692,472 @@ IopParseDevice(IN PVOID ParseObject,
                                    AccessGranted,
                                    UserMode,
                                    &AccessState->GenerateOnClose);
-        }
-        else
-        {
-            /* Check if we need to do traverse validation */
-            if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
-                ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
-                 (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
-            {
-                /* Check if this is a restricted token */
-                if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
-                {
-                    /* Do the FAST traverse check */
-                    AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
-                                                        AccessState,
-                                                        FILE_TRAVERSE,
-                                                        UserMode);
-                }
-                else
-                {
-                    /* Fail */
-                    AccessGranted = FALSE;
-                }
 
-                /* Check if we failed to get access */
-                if (!AccessGranted)
-                {
-                    /* Lock the subject context */
-                    SeLockSubjectContext(&AccessState->SubjectSecurityContext);
-                    LockHeld = TRUE;
+            SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
 
-                    /* Do access check */
-                    AccessGranted = SeAccessCheck(OriginalDeviceObject->
-                                                  SecurityDescriptor,
-                                                  &AccessState->SubjectSecurityContext,
-                                                  LockHeld,
-                                                  FILE_TRAVERSE,
-                                                  0,
-                                                  &Privileges,
-                                                  &IoFileObjectType->
-                                                  TypeInfo.GenericMapping,
-                                                  UserMode,
-                                                  &GrantedAccess,
-                                                  &Status);
-                    if (Privileges)
-                    {
-                        /* Append and free the privileges */
-                        SeAppendPrivileges(AccessState, Privileges);
-                        SeFreePrivileges(Privileges);
-                    }
-                }
+            ExReleaseResourceLite(&IopSecurityResource);
+            KeLeaveCriticalRegion();
 
-                /* FIXME: Do Audit/Alarm for traverse check */
-            }
-            else
+            /* Check if access failed */
+            if (!AccessGranted)
             {
-                /* Access automatically granted */
-                AccessGranted = TRUE;
+                /* Dereference the device and fail */
+                IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+                if (Vpb) IopDereferenceVpbAndFree(Vpb);
+                return STATUS_ACCESS_DENIED;
             }
         }
 
-        /* Check if we hold the lock */
-        if (LockHeld)
+        /* Allocate the IRP */
+        Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
+        if (!Irp)
         {
-            /* Release it */
-            SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
-        }
-
-        /* Check if access failed */
-        if (!AccessGranted)
-        {
-            /* Dereference the device and fail */
-            DPRINT1("Traverse access failed!\n");
+            /* Dereference the device and VPB, then fail */
             IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
-            return STATUS_ACCESS_DENIED;
+            if (Vpb) IopDereferenceVpbAndFree(Vpb);
+            return STATUS_INSUFFICIENT_RESOURCES;
         }
-    }
-
-    /* Check if we can simply use a dummy file */
-    UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
-
-    /* Check if this is a direct open */
-    if (!(RemainingName->Length) &&
-        !(OpenPacket->RelatedFileObject) &&
-        ((DesiredAccess & ~(SYNCHRONIZE |
-                            FILE_READ_ATTRIBUTES |
-                            READ_CONTROL |
-                            ACCESS_SYSTEM_SECURITY |
-                            WRITE_OWNER |
-                            WRITE_DAC)) == 0) &&
-        !(UseDummyFile))
-    {
-        /* Remember this for later */
-        DirectOpen = TRUE;
-    }
 
-    /* FIXME: Small hack still exists, have to check why...
-     * This is triggered multiple times by usetup and then once per boot.
-     */
-    if (!(DirectOpen) &&
-        !(RemainingName->Length) &&
-        !(OpenPacket->RelatedFileObject) &&
-        ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
-         (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
-        !(UseDummyFile))
-    {
-        DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
-        DesiredAccess & ~(SYNCHRONIZE |
-                          FILE_READ_ATTRIBUTES |
-                          READ_CONTROL |
-                          ACCESS_SYSTEM_SECURITY |
-                          WRITE_OWNER |
-                          WRITE_DAC));
-        DirectOpen = TRUE;
-    }
-
-    /* Check if we have a related FO that wasn't a direct open */
-    if ((OpenPacket->RelatedFileObject) &&
-        !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
-    {
-        /* The device object is the one we were given */
-        DeviceObject = ParseObject;
+        /* Now set the IRP data */
+        Irp->RequestorMode = AccessMode;
+        Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
+        Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+        Irp->UserIosb = &IoStatusBlock;
+        Irp->MdlAddress = NULL;
+        Irp->PendingReturned = FALSE;
+        Irp->UserEvent = NULL;
+        Irp->Cancel = FALSE;
+        Irp->CancelRoutine = NULL;
+        Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
+
+        /* Setup the security context */
+        SecurityContext.SecurityQos = SecurityQos;
+        SecurityContext.AccessState = AccessState;
+        SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
+        SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
+
+        /* Get the I/O Stack location */
+        StackLoc = IoGetNextIrpStackLocation(Irp);
+        StackLoc->Control = 0;
+
+        /* Check what kind of file this is */
+        switch (OpenPacket->CreateFileType)
+        {
+            /* Normal file */
+            case CreateFileTypeNone:
+
+                /* Set the major function and EA Length */
+                StackLoc->MajorFunction = IRP_MJ_CREATE;
+                StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
+
+                /* Set the flags */
+                StackLoc->Flags = (UCHAR)OpenPacket->Options;
+                StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
+                break;
+
+            /* Named pipe */
+            case CreateFileTypeNamedPipe:
+
+                /* Set the named pipe MJ and set the parameters */
+                StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
+                StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
+                break;
+
+            /* Mailslot */
+            case CreateFileTypeMailslot:
+
+                /* Set the mailslot MJ and set the parameters */
+                StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
+                StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
+                break;
+        }
+
+        /* Set the common data */
+        Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
+        Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
+        StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
+                                              (OpenPacket->CreateOptions &
+                                               0xFFFFFF);
+        StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
+        StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
+        StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
+
+        /* Check if we really need to create an object */
+        if (!UseDummyFile)
+        {
+            ULONG ObjectSize = sizeof(FILE_OBJECT);
+
+            /* Tag on space for a file object extension */
+            if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
+                ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
+
+            /* Create the actual file object */
+            InitializeObjectAttributes(&ObjectAttributes,
+                                       NULL,
+                                       Attributes,
+                                       NULL,
+                                       NULL);
+            Status = ObCreateObject(KernelMode,
+                                    IoFileObjectType,
+                                    &ObjectAttributes,
+                                    AccessMode,
+                                    NULL,
+                                    ObjectSize,
+                                    0,
+                                    0,
+                                    (PVOID*)&FileObject);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Create failed, free the IRP */
+                IoFreeIrp(Irp);
 
-        /* Check if the related FO had a VPB */
-        if (OpenPacket->RelatedFileObject->Vpb)
-        {
-            /* Yes, remember it */
-            Vpb = OpenPacket->RelatedFileObject->Vpb;
+                /* Dereference the device and VPB */
+                IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+                if (Vpb) IopDereferenceVpbAndFree(Vpb);
 
-            /* Reference it */
-            InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
-        }
-    }
-    else
-    {
-        /* The device object is the one we were given */
-        DeviceObject = OriginalDeviceObject;
+                /* We failed, return status */
+                OpenPacket->FinalStatus = Status;
+                return Status;
+            }
 
-        /* Check if it has a VPB */
-        if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
-        {
-            /* Check if the VPB is mounted, and mount it */
-            Vpb = IopCheckVpbMounted(OpenPacket,
-                                     OriginalDeviceObject,
-                                     RemainingName,
-                                     &Status);
-            if (!Vpb) return Status;
+            /* Clear the file object */
+            RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
 
-            /* Get the VPB's device object */
-            DeviceObject = Vpb->DeviceObject;
-        }
+            /* Check if this is Synch I/O */
+            if (OpenPacket->CreateOptions &
+                (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
+            {
+                /* Set the synch flag */
+                FileObject->Flags |= FO_SYNCHRONOUS_IO;
 
-        /* Check if there's an attached device */
-        if (DeviceObject->AttachedDevice)
-        {
-            /* Get the attached device */
-            DeviceObject = IoGetAttachedDevice(DeviceObject);
-        }
-    }
+                /* Check if it's also alertable */
+                if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
+                {
+                    /* It is, set the alertable flag */
+                    FileObject->Flags |= FO_ALERTABLE_IO;
+                }
+            }
 
-    /* Check if this is a secure FSD */
-    if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
-        ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
-        (!VolumeOpen))
-    {
-        DPRINT("Fix Secure FSD support!!!\n");
-    }
+            /* Check if this is synch I/O */
+            if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+            {
+                /* Initialize the event */
+                KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
+            }
 
-    /* Allocate the IRP */
-    Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
-    if (!Irp)
-    {
-        /* Dereference the device and VPB, then fail */
-        IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
-        if (Vpb) IopDereferenceVpbAndFree(Vpb);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+            /* Check if the caller requested no intermediate buffering */
+            if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
+            {
+                /* Set the correct flag for the FSD to read */
+                FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
+            }
 
-    /* Now set the IRP data */
-    Irp->RequestorMode = AccessMode;
-    Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
-    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
-    Irp->UserIosb = &IoStatusBlock;
-    Irp->MdlAddress = NULL;
-    Irp->PendingReturned = FALSE;
-    Irp->UserEvent = NULL;
-    Irp->Cancel = FALSE;
-    Irp->CancelRoutine = NULL;
-    Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
-
-    /* Setup the security context */
-    SecurityContext.SecurityQos = SecurityQos;
-    SecurityContext.AccessState = AccessState;
-    SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
-    SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
-
-    /* Get the I/O Stack location */
-    StackLoc = (PEXTENDED_IO_STACK_LOCATION)IoGetNextIrpStackLocation(Irp);
-    StackLoc->Control = 0;
-
-    /* Check what kind of file this is */
-    switch (OpenPacket->CreateFileType)
-    {
-        /* Normal file */
-        case CreateFileTypeNone:
-
-            /* Set the major function and EA Length */
-            StackLoc->MajorFunction = IRP_MJ_CREATE;
-            StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
-
-            /* Set the flags */
-            StackLoc->Flags = (UCHAR)OpenPacket->Options;
-            StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
-            break;
+            /* Check if the caller requested write through support */
+            if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
+            {
+                /* Set the correct flag for the FSD to read */
+                FileObject->Flags |= FO_WRITE_THROUGH;
+            }
 
-        /* Named pipe */
-        case CreateFileTypeNamedPipe:
+            /* Check if the caller says the file will be only read sequentially */
+            if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
+            {
+                /* Set the correct flag for the FSD to read */
+                FileObject->Flags |= FO_SEQUENTIAL_ONLY;
+            }
 
-            /* Set the named pipe MJ and set the parameters */
-            StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
-            StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
-            break;
+            /* Check if the caller believes the file will be only read randomly */
+            if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
+            {
+                /* Set the correct flag for the FSD to read */
+                FileObject->Flags |= FO_RANDOM_ACCESS;
+            }
 
-        /* Mailslot */
-        case CreateFileTypeMailslot:
+            /* Check if we were asked to setup a file object extension */
+            if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
+            {
+                PFILE_OBJECT_EXTENSION FileObjectExtension;
 
-            /* Set the mailslot MJ and set the parameters */
-            StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
-            StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
-            break;
-    }
+                /* Make sure the file object knows it has an extension */
+                FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
 
-    /* Set the common data */
-    Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
-    Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
-    StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
-                                          (OpenPacket->CreateOptions &
-                                           0xFFFFFF);
-    StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
-    StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
-    StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
+                FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
+                FileObject->FileObjectExtension = FileObjectExtension;
 
-    /* Check if we really need to create an object */
-    if (!UseDummyFile)
-    {
-        /* Create the actual file object */
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   NULL,
-                                   Attributes,
-                                   NULL,
-                                   NULL);
-        Status = ObCreateObject(KernelMode,
-                                IoFileObjectType,
-                                &ObjectAttributes,
-                                AccessMode,
-                                NULL,
-                                sizeof(FILE_OBJECT),
-                                0,
-                                0,
-                                (PVOID*)&FileObject);
-        if (!NT_SUCCESS(Status))
+                /* Add the top level device which we'll send the request to */
+                if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
+                {
+                    FileObjectExtension->TopDeviceObjectHint = DeviceObject;
+                }
+            }
+        }
+        else
         {
-            /* Create failed, free the IRP */
-            IoFreeIrp(Irp);
-
-            /* Dereference the device and VPB */
-            IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
-            if (Vpb) IopDereferenceVpbAndFree(Vpb);
+            /* Use the dummy object instead */
+            LocalFileObject = OpenPacket->LocalFileObject;
+            RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
 
-            /* We failed, return status */
-            OpenPacket->FinalStatus = Status;
-            return Status;
+            /* Set it up */
+            FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
+            LocalFileObject->ObjectHeader.Type = IoFileObjectType;
+            LocalFileObject->ObjectHeader.PointerCount = 1;
         }
 
-        /* Clear the file object */
-        RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
+        /* Setup the file header */
+        FileObject->Type = IO_TYPE_FILE;
+        FileObject->Size = sizeof(FILE_OBJECT);
+        FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
+        FileObject->DeviceObject = OriginalDeviceObject;
+
+        /* Check if this is a direct device open */
+        if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
 
-        /* Check if this is Synch I/O */
-        if (OpenPacket->CreateOptions &
-            (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
+        /* Check if the caller wants case sensitivity */
+        if (!(Attributes & OBJ_CASE_INSENSITIVE))
         {
-            /* Set the synch flag */
-            FileObject->Flags |= FO_SYNCHRONOUS_IO;
+            /* Tell the driver about it */
+            FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
+        }
 
-            /* Check if it's also alertable */
-            if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
+        /* Now set the file object */
+        Irp->Tail.Overlay.OriginalFileObject = FileObject;
+        StackLoc->FileObject = FileObject;
+
+        /* Check if the file object has a name */
+        if (RemainingName->Length)
+        {
+            /* Setup the unicode string */
+            FileObject->FileName.MaximumLength = RemainingName->Length +
+                                                 sizeof(WCHAR);
+            FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                                FileObject->
+                                                                FileName.
+                                                                MaximumLength,
+                                                                TAG_IO_NAME);
+            if (!FileObject->FileName.Buffer)
             {
-                /* It is, set the alertable flag */
-                FileObject->Flags |= FO_ALERTABLE_IO;
+                /* Failed to allocate the name, free the IRP */
+                IoFreeIrp(Irp);
+
+                /* Dereference the device object and VPB */
+                IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+                if (Vpb) IopDereferenceVpbAndFree(Vpb);
+
+                /* Clear the FO and dereference it */
+                FileObject->DeviceObject = NULL;
+                if (!UseDummyFile) ObDereferenceObject(FileObject);
+
+                /* Fail */
+                return STATUS_INSUFFICIENT_RESOURCES;
             }
         }
 
-        /* Check if this is synch I/O */
-        if (FileObject->Flags & FO_SYNCHRONOUS_IO)
-        {
-            /* Initialize the event */
-            KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
-        }
+        /* Copy the name */
+        RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
 
-        /* Check if the caller requested no intermediate buffering */
-        if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
-        {
-            /* Set the correct flag for the FSD to read */
-            FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
-        }
+        /* Initialize the File Object event and set the FO */
+        KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
+        OpenPacket->FileObject = FileObject;
 
-        /* Check if the caller requested write through support */
-        if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
+        /* Queue the IRP and call the driver */
+        IopQueueIrpToThread(Irp);
+        Status = IoCallDriver(DeviceObject, Irp);
+        if (Status == STATUS_PENDING)
         {
-            /* Set the correct flag for the FSD to read */
-            FileObject->Flags |= FO_WRITE_THROUGH;
-        }
+            /* Wait for the driver to complete the create */
+            KeWaitForSingleObject(&FileObject->Event,
+                                  Executive,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
 
-        /* Check if the caller says the file will be only read sequentially */
-        if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
-        {
-            /* Set the correct flag for the FSD to read */
-            FileObject->Flags |= FO_SEQUENTIAL_ONLY;
+            /* Get the new status */
+            Status = IoStatusBlock.Status;
         }
-
-        /* Check if the caller believes the file will be only read randomly */
-        if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
+        else
         {
-            /* Set the correct flag for the FSD to read */
-            FileObject->Flags |= FO_RANDOM_ACCESS;
-        }
-    }
-    else
-    {
-        /* Use the dummy object instead */
-        LocalFileObject = OpenPacket->LocalFileObject;
-        RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
+            /* We'll have to complete it ourselves */
+            ASSERT(!Irp->PendingReturned);
+            ASSERT(!Irp->MdlAddress);
 
-        /* Set it up */
-        FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
-        LocalFileObject->ObjectHeader.Type = IoFileObjectType;
-        LocalFileObject->ObjectHeader.PointerCount = 1;
-    }
+            /* Handle name change if required */
+            if (Status == STATUS_REPARSE)
+            {
+                /* Check this is a mount point */
+                if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
+                {
+                    PREPARSE_DATA_BUFFER ReparseData;
 
-    /* Setup the file header */
-    FileObject->Type = IO_TYPE_FILE;
-    FileObject->Size = sizeof(FILE_OBJECT);
-    FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
-    FileObject->DeviceObject = OriginalDeviceObject;
+                    /* Reparse point attributes were passed by the driver in the auxiliary buffer */
+                    ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+                    ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
 
-    /* Check if this is a direct device open */
-    if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
+                    ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+                    ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+                    ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
 
-    /* Check if the caller wants case sensitivity */
-    if (!(Attributes & OBJ_CASE_INSENSITIVE))
-    {
-        /* Tell the driver about it */
-        FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
-    }
+                    IopDoNameTransmogrify(Irp, FileObject, ReparseData);
+                }
+            }
 
-    /* Now set the file object */
-    Irp->Tail.Overlay.OriginalFileObject = FileObject;
-    StackLoc->FileObject = FileObject;
-
-    /* Check if the file object has a name */
-    if (RemainingName->Length)
-    {
-        /* Setup the unicode string */
-        FileObject->FileName.MaximumLength = RemainingName->Length +
-                                             sizeof(WCHAR);
-        FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
-                                                            FileObject->
-                                                            FileName.
-                                                            MaximumLength,
-                                                            TAG_IO_NAME);
-        if (!FileObject->FileName.Buffer)
-        {
-            /* Failed to allocate the name, free the IRP */
-            IoFreeIrp(Irp);
+            /* Completion happens at APC_LEVEL */
+            KeRaiseIrql(APC_LEVEL, &OldIrql);
 
-            /* Dereference the device object and VPB */
-            IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
-            if (Vpb) IopDereferenceVpbAndFree(Vpb);
+            /* Get the new I/O Status block ourselves */
+            IoStatusBlock = Irp->IoStatus;
+            Status = IoStatusBlock.Status;
 
-            /* Clear the FO and dereference it */
-            FileObject->DeviceObject = NULL;
-            if (!UseDummyFile) ObDereferenceObject(FileObject);
+            /* Manually signal the even, we can't have any waiters */
+            FileObject->Event.Header.SignalState = 1;
 
-            /* Fail */
-            return STATUS_INSUFFICIENT_RESOURCES;
+            /* Now that we've signaled the events, de-associate the IRP */
+            IopUnQueueIrpFromThread(Irp);
+
+            /* Check if the IRP had an input buffer */
+            if ((Irp->Flags & IRP_BUFFERED_IO) &&
+                (Irp->Flags & IRP_DEALLOCATE_BUFFER))
+            {
+                /* Free it. A driver might've tacked one on */
+                ExFreePool(Irp->AssociatedIrp.SystemBuffer);
+            }
+
+            /* Free the IRP and bring the IRQL back down */
+            IoFreeIrp(Irp);
+            KeLowerIrql(OldIrql);
         }
-    }
 
-    /* Copy the name */
-    RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
+        /* Copy the I/O Status */
+        OpenPacket->Information = IoStatusBlock.Information;
 
-    /* Initialize the File Object event and set the FO */
-    KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
-    OpenPacket->FileObject = FileObject;
+        /* The driver failed to create the file */
+        if (!NT_SUCCESS(Status))
+        {
+            /* Check if we have a name */
+            if (FileObject->FileName.Length)
+            {
+                /* Free it */
+                ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+                FileObject->FileName.Length = 0;
+            }
 
-    /* Queue the IRP and call the driver */
-    IopQueueIrpToThread(Irp);
-    Status = IoCallDriver(DeviceObject, Irp);
-    if (Status == STATUS_PENDING)
-    {
-        /* Wait for the driver to complete the create */
-        KeWaitForSingleObject(&FileObject->Event,
-                              Executive,
-                              KernelMode,
-                              FALSE,
-                              NULL);
+            /* Clear its device object */
+            FileObject->DeviceObject = NULL;
 
-        /* Get the new status */
-        Status = IoStatusBlock.Status;
-    }
-    else
-    {
-        /* We'll have to complete it ourselves */
-        ASSERT(!Irp->PendingReturned);
-        ASSERT(!Irp->MdlAddress);
+            /* Save this now because the FO might go away */
+            OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
+                            TRUE : FALSE;
 
-        /* Completion happens at APC_LEVEL */
-        KeRaiseIrql(APC_LEVEL, &OldIrql);
+            /* Clear the file object in the open packet */
+            OpenPacket->FileObject = NULL;
 
-        /* Get the new I/O Status block ourselves */
-        IoStatusBlock = Irp->IoStatus;
-        Status = IoStatusBlock.Status;
+            /* Dereference the file object */
+            if (!UseDummyFile) ObDereferenceObject(FileObject);
 
-        /* Manually signal the even, we can't have any waiters */
-        FileObject->Event.Header.SignalState = 1;
+            /* Dereference the device object */
+            IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
 
-        /* Now that we've signaled the events, de-associate the IRP */
-        IopUnQueueIrpFromThread(Irp);
+            /* Unless the driver cancelled the open, dereference the VPB */
+            if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
 
-        /* Check if the IRP had an input buffer */
-        if ((Irp->Flags & IRP_BUFFERED_IO) &&
-            (Irp->Flags & IRP_DEALLOCATE_BUFFER))
-        {
-            /* Free it. A driver might've tacked one on */
-            ExFreePool(Irp->AssociatedIrp.SystemBuffer);
+            /* Set the status and return */
+            OpenPacket->FinalStatus = Status;
+            return Status;
         }
+        else if (Status == STATUS_REPARSE)
+        {
+            if (OpenPacket->Information == IO_REPARSE ||
+                OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+            {
+                /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
+                if (CompleteName->MaximumLength < FileObject->FileName.Length)
+                {
+                    PWSTR NewCompleteName;
 
-        /* Free the IRP and bring the IRQL back down */
-        IoFreeIrp(Irp);
-        KeLowerIrql(OldIrql);
-    }
+                    /* Allocate a new buffer for the string */
+                    NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
+                    if (NewCompleteName == NULL)
+                    {
+                        OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+                        return STATUS_INSUFFICIENT_RESOURCES;
+                    }
+
+                    /* Release the old one */
+                    if (CompleteName->Buffer != NULL)
+                    {
+                        ExFreePoolWithTag(CompleteName->Buffer, 0);
+                    }
+
+                    /* And setup the new one */
+                    CompleteName->Buffer = NewCompleteName;
+                    CompleteName->MaximumLength = FileObject->FileName.Length;
+                }
+
+                /* Copy our new complete name */
+                RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
+
+                if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+                {
+                    OpenPacket->RelatedFileObject = NULL;
+                }
+            }
+
+            /* Check if we have a name */
+            if (FileObject->FileName.Length)
+            {
+                /* Free it */
+                ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
+                FileObject->FileName.Length = 0;
+            }
+
+            /* Clear its device object */
+            FileObject->DeviceObject = NULL;
 
-    /* Copy the I/O Status */
-    OpenPacket->Information = IoStatusBlock.Information;
+            /* Clear the file object in the open packet */
+            OpenPacket->FileObject = NULL;
 
-    /* The driver failed to create the file */
-    if (!NT_SUCCESS(Status))
-    {
-        /* Check if we have a name */
-        if (FileObject->FileName.Length)
-        {
-            /* Free it */
-            ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
-            FileObject->FileName.Length = 0;
-        }
+            /* Dereference the file object */
+            if (!UseDummyFile) ObDereferenceObject(FileObject);
 
-        /* Clear its device object */
-        FileObject->DeviceObject = NULL;
+            /* Dereference the device object */
+            IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
 
-        /* Save this now because the FO might go away */
-        OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
-                        TRUE : FALSE;
+            /* Unless the driver cancelled the open, dereference the VPB */
+            if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
 
-        /* Clear the file object in the open packet */
-        OpenPacket->FileObject = NULL;
+            if (OpenPacket->Information != IO_REMOUNT)
+            {
+                OpenPacket->RelatedFileObject = NULL;
 
-        /* Dereference the file object */
-        if (!UseDummyFile) ObDereferenceObject(FileObject);
+                /* Inform we traversed a mount point for later attempt */
+                if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+                {
+                    OpenPacket->TraversedMountPoint = 1;
+                }
 
-        /* Dereference the device object */
-        IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+                /* In case we override checks, but got this on volume open, fail hard */
+                if (OpenPacket->Override)
+                {
+                    KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
+                                 (ULONG_PTR)OriginalDeviceObject,
+                                 (ULONG_PTR)DeviceObject,
+                                 (ULONG_PTR)CompleteName,
+                                 OpenPacket->Information);
+                }
 
-        /* Unless the driver cancelled the open, dereference the VPB */
-        if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
+                /* Return to IO/OB so that information can be upgraded */
+                return STATUS_REPARSE;
+            }
 
-        /* Set the status and return */
-        OpenPacket->FinalStatus = Status;
-        return Status;
-    }
-    else if (Status == STATUS_REPARSE)
-    {
-        /* FIXME: We don't handle this at all! */
-        ASSERT(FALSE);
+            /* Loop again and reattempt an opening */
+            continue;
+        }
+
+        break;
     }
 
+    if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
+        return STATUS_UNSUCCESSFUL;
+
     /* Get the owner of the File Object */
     OwnerDevice = IoGetRelatedDeviceObject(FileObject);
 
@@ -997,8 +1347,7 @@ IopDeleteFile(IN PVOID ObjectBody)
         KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
 
         /* Allocate an IRP */
-        Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-        if (!Irp) return;
+        Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
 
         /* Set it up */
         Irp->UserEvent = &Event;
@@ -1078,16 +1427,184 @@ IopDeleteFile(IN PVOID ObjectBody)
     }
 }
 
+PDEVICE_OBJECT
+NTAPI
+IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
+{
+    PDEVICE_OBJECT PDO = DeviceObject;
+
+    /* Go down the stack to attempt to get the PDO */
+    for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
+           PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
+
+    return PDO;
+}
+
+PDEVICE_OBJECT
+NTAPI
+IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
+{
+    KIRQL OldIrql;
+    PDEVICE_OBJECT PDO;
+
+    ASSERT(DeviceObject != NULL);
+
+    OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
+    /* Get the base DO */
+    PDO = IopGetDeviceAttachmentBase(DeviceObject);
+    /* Check whether that's really a PDO and if so, keep it */
+    if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
+    {
+        PDO = NULL;
+    }
+    else
+    {
+        ObReferenceObject(PDO);
+    }
+    KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
+
+    return PDO;
+}
+
+NTSTATUS
+NTAPI
+IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
+                               IN PSECURITY_INFORMATION SecurityInformation,
+                               IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+                               IN POOL_TYPE PoolType,
+                               IN PGENERIC_MAPPING GenericMapping)
+{
+    NTSTATUS Status;
+    PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
+
+    PAGED_CODE();
+
+    /* Keep attempting till we find our old SD or fail */
+    while (TRUE)
+    {
+        KeEnterCriticalRegion();
+        ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
+
+        /* Get our old SD and reference it */
+        OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
+        if (OldSecurityDescriptor != NULL)
+        {
+            ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+        }
+
+        ExReleaseResourceLite(&IopSecurityResource);
+        KeLeaveCriticalRegion();
+
+        /* Set the SD information */
+        NewSecurityDescriptor = OldSecurityDescriptor;
+        Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
+                                             SecurityDescriptor, &NewSecurityDescriptor,
+                                             PoolType, GenericMapping);
+
+        if (!NT_SUCCESS(Status))
+        {
+            if (OldSecurityDescriptor != NULL)
+            {
+                ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+            }
+
+            break;
+        }
+
+        /* Add the new DS to the internal cache */
+        Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
+                                         &CachedSecurityDescriptor, 1);
+        ExFreePool(NewSecurityDescriptor);
+        if (!NT_SUCCESS(Status))
+        {
+            ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+            break;
+        }
+
+        KeEnterCriticalRegion();
+        ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
+        /* Check if someone changed it in our back */
+        if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
+        {
+            /* We're clear, do the swap */
+            DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
+            ExReleaseResourceLite(&IopSecurityResource);
+            KeLeaveCriticalRegion();
+
+            /* And dereference old SD (twice - us + not in use) */
+            ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
+
+            break;
+        }
+        ExReleaseResourceLite(&IopSecurityResource);
+        KeLeaveCriticalRegion();
+
+        /* If so, try again */
+        ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+        ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
+                                IN PDEVICE_OBJECT PhysicalDeviceObject,
+                                IN PSECURITY_INFORMATION SecurityInformation,
+                                IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+                                IN POOL_TYPE PoolType,
+                                IN PGENERIC_MAPPING GenericMapping)
+{
+    PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
+    NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
+
+    PAGED_CODE();
+
+    ASSERT(PhysicalDeviceObject != NULL);
+
+    /* We always reference the DO we're working on */
+    ObReferenceObject(CurrentDO);
+
+    /* Go up from PDO to latest DO */
+    do
+    {
+        /* Attempt to set the new SD on it */
+        TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
+                                                   SecurityDescriptor, PoolType,
+                                                   GenericMapping);
+        /* Was our last one? Remember that status then */
+        if (CurrentDO == UpperDeviceObject)
+        {
+            Status = TmpStatus;
+        }
+
+        /* Try to move to the next DO (and thus, reference it) */
+        NextDevice = CurrentDO->AttachedDevice;
+        if (NextDevice)
+        {
+            ObReferenceObject(NextDevice);
+        }
+
+        /* Dereference current DO and move to the next one */
+        ObDereferenceObject(CurrentDO);
+        CurrentDO = NextDevice;
+    }
+    while (CurrentDO != NULL);
+
+    return Status;
+}
+
 NTSTATUS
 NTAPI
-IopSecurityFile(IN PVOID ObjectBody,
-                IN SECURITY_OPERATION_CODE OperationCode,
-                IN PSECURITY_INFORMATION SecurityInformation,
-                IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-                IN OUT PULONG BufferLength,
-                IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
-                IN POOL_TYPE PoolType,
-                IN OUT PGENERIC_MAPPING GenericMapping)
+IopGetSetSecurityObject(IN PVOID ObjectBody,
+                        IN SECURITY_OPERATION_CODE OperationCode,
+                        IN PSECURITY_INFORMATION SecurityInformation,
+                        IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+                        IN OUT PULONG BufferLength,
+                        IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
+                        IN POOL_TYPE PoolType,
+                        IN OUT PGENERIC_MAPPING GenericMapping)
 {
     IO_STATUS_BLOCK IoStatusBlock;
     PIO_STACK_LOCATION StackPtr;
@@ -1145,21 +1662,59 @@ IopSecurityFile(IN PVOID ObjectBody,
         }
         else if (OperationCode == AssignSecurityDescriptor)
         {
+            Status = STATUS_SUCCESS;
+
             /* Make absolutely sure this is a device object */
             if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
             {
-                /* Assign the Security Descriptor */
-                DeviceObject->SecurityDescriptor = SecurityDescriptor;
+                PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
+
+                /* Add the security descriptor in cache */
+                Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
+                if (NT_SUCCESS(Status))
+                {
+                    KeEnterCriticalRegion();
+                    ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
+
+                    /* Assign the Security Descriptor */
+                    DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
+
+                    ExReleaseResourceLite(&IopSecurityResource);
+                    KeLeaveCriticalRegion();
+                }
             }
 
-            /* Return success */
-            return STATUS_SUCCESS;
+            /* Return status */
+            return Status;
         }
-        else
+        else if (OperationCode == SetSecurityDescriptor)
         {
-            DPRINT1("FIXME: Set SD unimplemented for Devices\n");
+            /* Get the Physical Device Object if any */
+            PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
+
+            if (PDO != NULL)
+            {
+                /* Apply the new SD to any DO in the path from PDO to current DO */
+                Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
+                                                         SecurityInformation,
+                                                         SecurityDescriptor,
+                                                         PoolType, GenericMapping);
+                ObDereferenceObject(PDO);
+            }
+            else
+            {
+                /* Otherwise, just set for ourselves */
+                Status = IopSetDeviceSecurityDescriptor(DeviceObject,
+                                                        SecurityInformation,
+                                                        SecurityDescriptor,
+                                                        PoolType, GenericMapping);
+            }
+
             return STATUS_SUCCESS;
         }
+
+        /* Shouldn't happen */
+        return STATUS_SUCCESS;
     }
     else if (OperationCode == DeleteSecurityDescriptor)
     {
@@ -1447,6 +2002,7 @@ IopCloseFile(IN PEPROCESS Process OPTIONAL,
     NTSTATUS Status;
     PDEVICE_OBJECT DeviceObject;
     KIRQL OldIrql;
+    IO_STATUS_BLOCK IoStatusBlock;
     IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
 
     /* If this isn't the last handle for the current process, quit */
@@ -1455,8 +2011,71 @@ IopCloseFile(IN PEPROCESS Process OPTIONAL,
     /* Check if the file is locked and has more then one handle opened */
     if ((FileObject->LockOperation) && (SystemHandleCount != 1))
     {
-        DPRINT1("We need to unlock this file!\n");
-        ASSERT(FALSE);
+        /* Check if this is a direct open or not */
+        if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
+        {
+            /* Get the attached device */
+            DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
+        }
+        else
+        {
+            /* Get the FO's device */
+            DeviceObject = IoGetRelatedDeviceObject(FileObject);
+        }
+
+        /* Check if this is a sync FO and lock it */
+        if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+        {
+            IopLockFileObject(FileObject);
+        }
+
+        /* Go the FastIO path if possible, otherwise fall back to IRP */
+        if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
+            DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
+            !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
+        {
+            /* Clear and set up Events */
+            KeClearEvent(&FileObject->Event);
+            KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+            /* Allocate an IRP */
+            Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
+
+            /* Set it up */
+            Irp->UserEvent = &Event;
+            Irp->UserIosb = &Irp->IoStatus;
+            Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+            Irp->Tail.Overlay.OriginalFileObject = FileObject;
+            Irp->RequestorMode = KernelMode;
+            Irp->Flags = IRP_SYNCHRONOUS_API;
+            Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
+            ObReferenceObject(FileObject);
+
+            /* Set up Stack Pointer Data */
+            StackPtr = IoGetNextIrpStackLocation(Irp);
+            StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
+            StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
+            StackPtr->FileObject = FileObject;
+
+            /* Queue the IRP */
+            IopQueueIrpToThread(Irp);
+
+            /* Call the FS Driver */
+            Status = IoCallDriver(DeviceObject, Irp);
+            if (Status == STATUS_PENDING)
+            {
+                /* Wait for completion */
+                KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
+            }
+
+            /* IO will unqueue & free for us */
+        }
+
+        /* Release the lock if we were holding it */
+        if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+        {
+            IopUnlockFileObject(FileObject);
+        }
     }
 
     /* Make sure this is the last handle */
@@ -1478,15 +2097,18 @@ IopCloseFile(IN PEPROCESS Process OPTIONAL,
     FileObject->Flags |= FO_HANDLE_CREATED;
 
     /* Check if this is a sync FO and lock it */
-    if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopLockFileObject(FileObject);
+    if (Process != NULL &&
+        BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+    {
+        IopLockFileObject(FileObject);
+    }
 
     /* Clear and set up Events */
     KeClearEvent(&FileObject->Event);
     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
 
     /* Allocate an IRP */
-    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp) return;
+    Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
 
     /* Set it up */
     Irp->UserEvent = &Event;
@@ -1524,7 +2146,11 @@ IopCloseFile(IN PEPROCESS Process OPTIONAL,
     IoFreeIrp(Irp);
 
     /* Release the lock if we were holding it */
-    if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
+    if (Process != NULL &&
+        BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+    {
+        IopUnlockFileObject(FileObject);
+    }
 }
 
 NTSTATUS
@@ -1597,9 +2223,11 @@ IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
                                 FILE_READ_ATTRIBUTES,
                                 &OpenPacket,
                                 &Handle);
-    if (OpenPacket.ParseCheck != TRUE)
+    if (OpenPacket.ParseCheck == FALSE)
     {
         /* Parse failed */
+        DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
+               ObjectAttributes->ObjectName, Status);
         return Status;
     }
     else
@@ -1661,53 +2289,24 @@ IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
     return STATUS_NOT_IMPLEMENTED;
 }
 
-/* FUNCTIONS *****************************************************************/
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
-                               IN ULONG Length,
-                               IN BOOLEAN SetOperation)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
-                           IN ULONG QuotaLength,
-                           OUT PULONG ErrorOffset)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @implemented
- */
 NTSTATUS
 NTAPI
-IoCreateFile(OUT PHANDLE FileHandle,
-             IN ACCESS_MASK DesiredAccess,
-             IN POBJECT_ATTRIBUTES ObjectAttributes,
-             OUT PIO_STATUS_BLOCK IoStatusBlock,
-             IN PLARGE_INTEGER AllocationSize OPTIONAL,
-             IN ULONG FileAttributes,
-             IN ULONG ShareAccess,
-             IN ULONG Disposition,
-             IN ULONG CreateOptions,
-             IN PVOID EaBuffer OPTIONAL,
-             IN ULONG EaLength,
-             IN CREATE_FILE_TYPE CreateFileType,
-             IN PVOID ExtraCreateParameters OPTIONAL,
-             IN ULONG Options)
+IopCreateFile(OUT PHANDLE FileHandle,
+              IN ACCESS_MASK DesiredAccess,
+              IN POBJECT_ATTRIBUTES ObjectAttributes,
+              OUT PIO_STATUS_BLOCK IoStatusBlock,
+              IN PLARGE_INTEGER AllocationSize OPTIONAL,
+              IN ULONG FileAttributes,
+              IN ULONG ShareAccess,
+              IN ULONG Disposition,
+              IN ULONG CreateOptions,
+              IN PVOID EaBuffer OPTIONAL,
+              IN ULONG EaLength,
+              IN CREATE_FILE_TYPE CreateFileType,
+              IN PVOID ExtraCreateParameters OPTIONAL,
+              IN ULONG Options,
+              IN ULONG Flags,
+              IN PDEVICE_OBJECT DeviceObject OPTIONAL)
 {
     KPROCESSOR_MODE AccessMode;
     HANDLE LocalHandle = 0;
@@ -1717,6 +2316,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
     POPEN_PACKET OpenPacket;
     ULONG EaErrorOffset;
     PAGED_CODE();
+
     IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
 
 
@@ -1822,6 +2422,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
             /* Make sure we have extra parameters */
             if (!ExtraCreateParameters)
             {
+                DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
                 return STATUS_INVALID_PARAMETER;
             }
 
@@ -1835,6 +2436,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
                 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
             {
                 /* Invalid named pipe create */
+                DPRINT1("Invalid named pipe create\n");
                 return STATUS_INVALID_PARAMETER;
             }
         }
@@ -1843,6 +2445,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
             /* Make sure we have extra parameters */
             if (!ExtraCreateParameters)
             {
+                DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
                 return STATUS_INVALID_PARAMETER;
             }
 
@@ -1853,6 +2456,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
                 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
             {
                 /* Invalid mailslot create */
+                DPRINT1("Invalid mailslot create\n");
                 return STATUS_INVALID_PARAMETER;
             }
         }
@@ -1956,6 +2560,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
             if (!OpenPacket->EaBuffer)
             {
                 ExFreePool(OpenPacket);
+                DPRINT1("Failed to allocate open packet EA buffer\n");
                 return STATUS_INSUFFICIENT_RESOURCES;
             }
 
@@ -1991,6 +2596,8 @@ IoCreateFile(OUT PHANDLE FileHandle,
     OpenPacket->Disposition = Disposition;
     OpenPacket->CreateFileType = CreateFileType;
     OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
+    OpenPacket->InternalFlags = Flags;
+    OpenPacket->TopDeviceObjectHint = DeviceObject;
 
     /* Update the operation count */
     IopUpdateOperationCount(IopOtherTransfer);
@@ -2015,7 +2622,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
     if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
 
     /* Now check for Ob or Io failure */
-    if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck != TRUE))
+    if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
     {
         /* Check if Ob thinks well went well */
         if (NT_SUCCESS(Status))
@@ -2052,7 +2659,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
                 _SEH2_END;
             }
         }
-        else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck != 1))
+        else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
         {
             /*
              * This can happen in the very bizarre case where the parse routine
@@ -2096,7 +2703,7 @@ IoCreateFile(OUT PHANDLE FileHandle,
     }
 
     /* Check if we were 100% successful */
-    if ((OpenPacket->ParseCheck == TRUE) && (OpenPacket->FileObject))
+    if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
     {
         /* Dereference the File Object */
         ObDereferenceObject(OpenPacket->FileObject);
@@ -2107,6 +2714,74 @@ IoCreateFile(OUT PHANDLE FileHandle,
     return Status;
 }
 
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
+                               IN ULONG Length,
+                               IN BOOLEAN SetOperation)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
+                           IN ULONG QuotaLength,
+                           OUT PULONG ErrorOffset)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+IoCreateFile(OUT PHANDLE FileHandle,
+             IN ACCESS_MASK DesiredAccess,
+             IN POBJECT_ATTRIBUTES ObjectAttributes,
+             OUT PIO_STATUS_BLOCK IoStatusBlock,
+             IN PLARGE_INTEGER AllocationSize OPTIONAL,
+             IN ULONG FileAttributes,
+             IN ULONG ShareAccess,
+             IN ULONG Disposition,
+             IN ULONG CreateOptions,
+             IN PVOID EaBuffer OPTIONAL,
+             IN ULONG EaLength,
+             IN CREATE_FILE_TYPE CreateFileType,
+             IN PVOID ExtraCreateParameters OPTIONAL,
+             IN ULONG Options)
+{
+    PAGED_CODE();
+
+    return IopCreateFile(FileHandle,
+                         DesiredAccess,
+                         ObjectAttributes,
+                         IoStatusBlock,
+                         AllocationSize,
+                         FileAttributes,
+                         ShareAccess,
+                         Disposition,
+                         CreateOptions,
+                         EaBuffer,
+                         EaLength,
+                         CreateFileType,
+                         ExtraCreateParameters,
+                         Options,
+                         0,
+                         NULL);
+}
+
 /*
  * @unimplemented
  */
@@ -2128,8 +2803,33 @@ IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
                                     IN ULONG Options,
                                     IN PVOID DeviceObject)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    ULONG Flags = 0;
+
+    PAGED_CODE();
+
+    /* Check if we were passed a device to send the create request to*/
+    if (DeviceObject)
+    {
+        /* We'll tag this request into a file object extension */
+        Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
+    }
+
+    return IopCreateFile(FileHandle,
+                         DesiredAccess,
+                         ObjectAttributes,
+                         IoStatusBlock,
+                         AllocationSize,
+                         FileAttributes,
+                         ShareAccess,
+                         Disposition,
+                         CreateOptions,
+                         EaBuffer,
+                         EaLength,
+                         CreateFileType,
+                         ExtraCreateParameters,
+                         Options | IO_NO_PARAMETER_CHECKING,
+                         Flags,
+                         DeviceObject);
 }
 
 /*
@@ -2367,7 +3067,7 @@ IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
                                 DesiredAccess,
                                 &OpenPacket,
                                 &Handle);
-    if (OpenPacket.ParseCheck != TRUE)
+    if (OpenPacket.ParseCheck == FALSE)
     {
         /* Parse failed */
         IoStatus->Status = Status;
@@ -3180,7 +3880,7 @@ NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
                                 DELETE,
                                 &OpenPacket,
                                 &Handle);
-    if (OpenPacket.ParseCheck != TRUE) return Status;
+    if (OpenPacket.ParseCheck == FALSE) return Status;
 
     /* Retrn the Io status */
     return OpenPacket.FinalStatus;