- ObpCreateDosDevicesDirectory: Check that allocation succeeded before dereference
[reactos.git] / reactos / ntoskrnl / ob / obname.c
index fe15162..c97d4ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:         ReactOS Kernel
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/ob/namespce.c
+ * FILE:            ntoskrnl/ob/obname.c
  * PURPOSE:         Manages all functions related to the Object Manager name-
  *                  space, such as finding objects or querying their names.
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
 
 /* INCLUDES ******************************************************************/
 
-#define NTDDI_VERSION NTDDI_WINXP
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
-POBJECT_DIRECTORY NameSpaceRoot = NULL;
-POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL;
+BOOLEAN ObpCaseInsensitive = TRUE;
+POBJECT_DIRECTORY ObpRootDirectoryObject;
+POBJECT_DIRECTORY ObpTypeDirectoryObject;
+
+/* DOS Device Prefix \??\ and \?? */
+ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\\',L'?',L'?',L'\\'}};
+ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\\',L'?',L'?',L'\0'}};
+UNICODE_STRING ObpDosDevicesShortName =
+{
+    sizeof(ObpDosDevicesShortNamePrefix),
+    sizeof(ObpDosDevicesShortNamePrefix),
+    (PWSTR)&ObpDosDevicesShortNamePrefix
+};
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
+NTSTATUS
+NTAPI
+ObpCreateDosDevicesDirectory(VOID)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING Name, LinkName;
+    HANDLE Handle, SymHandle;
+    NTSTATUS Status;
+
+    /* Create the '\??' directory */
+    RtlInitUnicodeString(&Name, L"\\??");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &Name,
+                               OBJ_PERMANENT,
+                               NULL,
+                               NULL);
+    Status = NtCreateDirectoryObject(&Handle,
+                                     DIRECTORY_ALL_ACCESS,
+                                     &ObjectAttributes);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Initialize the GLOBALROOT path */
+    RtlInitUnicodeString(&LinkName, L"GLOBALROOT");
+    RtlInitUnicodeString(&Name, L"");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_PERMANENT,
+                               Handle,
+                               NULL);
+    Status = NtCreateSymbolicLinkObject(&SymHandle,
+                                        SYMBOLIC_LINK_ALL_ACCESS,
+                                        &ObjectAttributes,
+                                        &Name);
+    if (NT_SUCCESS(Status)) NtClose(SymHandle);
+
+    /* Link \??\Global to \?? */
+    RtlInitUnicodeString(&LinkName, L"Global");
+    RtlInitUnicodeString(&Name, L"\\??");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_PERMANENT,
+                               Handle,
+                               NULL);
+    Status = NtCreateSymbolicLinkObject(&SymHandle,
+                                        SYMBOLIC_LINK_ALL_ACCESS,
+                                        &ObjectAttributes,
+                                        &Name);
+    if (NT_SUCCESS(Status)) NtClose(SymHandle);
+
+    /* Close the directory handle */
+    NtClose(Handle);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Create link from '\DosDevices' to '\??' directory */
+    RtlCreateUnicodeString(&LinkName, L"\\DosDevices");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_PERMANENT,
+                               NULL,
+                               NULL);
+    Status = NtCreateSymbolicLinkObject(&SymHandle,
+                                        SYMBOLIC_LINK_ALL_ACCESS,
+                                        &ObjectAttributes,
+                                        &Name);
+    if (NT_SUCCESS(Status)) NtClose(SymHandle);
+
+    /* FIXME: Hack Hack! */
+    ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool,
+                                              sizeof(*ObSystemDeviceMap),
+                                              'mDbO');
+    if (!ObSystemDeviceMap) return STATUS_INSUFFICIENT_RESOURCES;
+    RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap));
+
+    /* Return status */
+    return Status;
+}
+
 VOID
 NTAPI
 ObDereferenceDeviceMap(IN PEPROCESS Process)
@@ -93,7 +180,7 @@ ObpDeleteNameCheck(IN PVOID Object)
 
     /* Get object structures */
     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
-    ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+    ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
     ObjectType = ObjectHeader->Type;
 
     /*
@@ -103,89 +190,135 @@ ObpDeleteNameCheck(IN PVOID Object)
     if (!(ObjectHeader->HandleCount) &&
          (ObjectNameInfo) &&
          (ObjectNameInfo->Name.Length) &&
+         (ObjectNameInfo->Directory) &&
          !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
     {
-        /* Make sure it's still inserted */
-        Context.Directory = ObjectNameInfo->Directory;
-        Context.DirectoryLocked = TRUE;
+        /* Setup a lookup context */
+        ObpInitializeLookupContext(&Context);
+
+        /* Lock the directory */
+        ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context);
+
+        /* Do the lookup */
         Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory,
                                          &ObjectNameInfo->Name,
                                          0,
                                          FALSE,
                                          &Context);
-        if ((Object) && !(ObjectHeader->HandleCount))
+        if (Object)
         {
-            /* First delete it from the directory */
-            ObpDeleteEntryDirectory(&Context);
+            /* Lock the object */
+            ObpAcquireObjectLock(ObjectHeader);
 
-            /* Now check if we have a security callback */
-            if (ObjectType->TypeInfo.SecurityRequired)
+            /* Make sure we can still delete the object */
+            if (!(ObjectHeader->HandleCount) &&
+                !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
             {
-                /* Call it */
-                ObjectType->TypeInfo.SecurityProcedure(Object,
-                                                       DeleteSecurityDescriptor,
-                                                       0,
-                                                       NULL,
-                                                       NULL,
-                                                       &ObjectHeader->
-                                                       SecurityDescriptor,
-                                                       ObjectType->
-                                                       TypeInfo.PoolType,
-                                                       NULL);
-            }
+                /* First delete it from the directory */
+                ObpDeleteEntryDirectory(&Context);
 
-            /* Free the name */
-            ExFreePool(ObjectNameInfo->Name.Buffer);
-            RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
+                /* Check if this is a symbolic link */
+                if (ObjectType == ObSymbolicLinkType)
+                {
+                    /* Remove internal name */
+                    ObpDeleteSymbolicLinkName(Object);
+                }
+
+                /* Check if the magic protection flag is set */
+                ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+                if ((ObjectNameInfo) &&
+                    (ObjectNameInfo->QueryReferences & 0x40000000))
+                {
+                    /* Remove protection flag */
+                    InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences,
+                                           -0x40000000);
+                }
+
+                /* Get the directory */
+                Directory = ObjectNameInfo->Directory;
+            }
 
-            /* Clear the current directory and de-reference it */
-            Directory = ObjectNameInfo->Directory;
-            ObjectNameInfo->Directory = NULL;
+            /* Release the lock */
+            ObpReleaseObjectLock(ObjectHeader);
         }
 
+        /* Cleanup after lookup */
+        ObpReleaseLookupContext(&Context);
+
+        /* Remove another query reference since we added one on top */
+        ObpDereferenceNameInfo(ObjectNameInfo);
+
         /* Check if we were inserted in a directory */
         if (Directory)
         {
-            /* We were, so dereference the directory and the object as well */
-            ObDereferenceObject(Directory);
+            /* We were, so first remove the extra reference we had added */
+            ObpDereferenceNameInfo(ObjectNameInfo);
+
+            /* Now dereference the object as well */
             ObDereferenceObject(Object);
         }
     }
+    else
+    {
+        /* Remove the reference we added */
+        ObpDereferenceNameInfo(ObjectNameInfo);
+    }
 }
 
 NTSTATUS
 NTAPI
-ObFindObject(IN HANDLE RootHandle,
-             IN PUNICODE_STRING ObjectName,
-             IN ULONG Attributes,
-             IN KPROCESSOR_MODE AccessMode,
-             IN PVOID *ReturnedObject,
-             IN POBJECT_TYPE ObjectType,
-             IN POBP_LOOKUP_CONTEXT Context,
-             IN PACCESS_STATE AccessState,
-             IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
-             IN PVOID ParseContext,
-             OUT PVOID ExpectedObject)
+ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,
+                    IN PUNICODE_STRING ObjectName,
+                    IN ULONG Attributes,
+                    IN POBJECT_TYPE ObjectType,
+                    IN KPROCESSOR_MODE AccessMode,
+                    IN OUT PVOID ParseContext,
+                    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+                    IN PVOID InsertObject OPTIONAL,
+                    IN OUT PACCESS_STATE AccessState,
+                    OUT POBP_LOOKUP_CONTEXT LookupContext,
+                    OUT PVOID *FoundObject)
 {
-    PVOID RootDirectory;
-    PVOID CurrentDirectory = NULL;
-    PVOID CurrentObject = NULL;
-    POBJECT_HEADER CurrentHeader;
-    NTSTATUS Status = STATUS_SUCCESS;
-    PVOID NewName;
-    POBJECT_HEADER_NAME_INFO ObjectNameInfo;
-    UNICODE_STRING RemainingPath, PartName;
-    BOOLEAN InsideRoot = FALSE;
+    PVOID Object;
+    POBJECT_HEADER ObjectHeader;
+    UNICODE_STRING ComponentName, RemainingName;
+    BOOLEAN Reparse = FALSE, SymLink = FALSE;
+    POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
+    POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
+    KIRQL CalloutIrql;
     OB_PARSE_METHOD ParseRoutine;
+    NTSTATUS Status;
+    KPROCESSOR_MODE AccessCheckMode;
+    PWCHAR NewName;
+    POBJECT_HEADER_NAME_INFO ObjectNameInfo;
+    ULONG MaxReparse = 30;
     PAGED_CODE();
-
-    /* Assume failure */
     OBTRACE(OB_NAMESPACE_DEBUG,
             "%s - Finding Object: %wZ. Expecting: %p\n",
             __FUNCTION__,
             ObjectName,
-            ExpectedObject);
-    *ReturnedObject = NULL;
+            InsertObject);
+
+    /* Initialize starting state */
+    ObpInitializeLookupContext(LookupContext);
+    *FoundObject = NULL;
+    Status = STATUS_SUCCESS;
+    Object = NULL;
+
+    /* Check if case-insensitivity is checked */
+    if (ObpCaseInsensitive)
+    {
+        /* Check if the object type requests this */
+        if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive))
+        {
+            /* Add the flag to disable case sensitivity */
+            Attributes |= OBJ_CASE_INSENSITIVE;
+        }
+    }
+
+    /* Check if this is a access checks are being forced */
+    AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ?
+                       UserMode : AccessMode;
 
     /* Check if we got a Root Directory */
     if (RootHandle)
@@ -195,17 +328,17 @@ ObFindObject(IN HANDLE RootHandle,
                                            0,
                                            NULL,
                                            AccessMode,
-                                           &RootDirectory,
+                                           (PVOID*)&RootDirectory,
                                            NULL);
         if (!NT_SUCCESS(Status)) return Status;
 
         /* Get the header */
-        CurrentHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
+        ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
 
         /* The name cannot start with a separator, unless this is a file */
         if ((ObjectName->Buffer) &&
             (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
-            (CurrentHeader->Type != IoFileObjectType))
+            (ObjectHeader->Type != IoFileObjectType))
         {
             /* The syntax is bad, so fail this request */
             ObDereferenceObject(RootDirectory);
@@ -213,10 +346,10 @@ ObFindObject(IN HANDLE RootHandle,
         }
 
         /* Don't parse a Directory */
-        if (CurrentHeader->Type != ObDirectoryType)
+        if (ObjectHeader->Type != ObDirectoryType)
         {
             /* Make sure the Object Type has a parse routine */
-            ParseRoutine = CurrentHeader->Type->TypeInfo.ParseProcedure;
+            ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
             if (!ParseRoutine)
             {
                 /* We can't parse a name if we don't have a parse routine */
@@ -224,23 +357,28 @@ ObFindObject(IN HANDLE RootHandle,
                 return STATUS_INVALID_HANDLE;
             }
 
+            /* Set default parse count */
+            MaxReparse = 30;
+
             /* Now parse */
             while (TRUE)
             {
                 /* Start with the full name */
-                RemainingPath = *ObjectName;
+                RemainingName = *ObjectName;
 
                 /* Call the Parse Procedure */
+                ObpCalloutStart(&CalloutIrql);
                 Status = ParseRoutine(RootDirectory,
                                       ObjectType,
                                       AccessState,
-                                      AccessMode,
+                                      AccessCheckMode,
                                       Attributes,
                                       ObjectName,
-                                      &RemainingPath,
+                                      &RemainingName,
                                       ParseContext,
                                       SecurityQos,
-                                      &CurrentObject);
+                                      &Object);
+                ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
 
                 /* Check for success or failure, so not reparse */
                 if ((Status != STATUS_REPARSE) &&
@@ -250,16 +388,16 @@ ObFindObject(IN HANDLE RootHandle,
                     if (!NT_SUCCESS(Status))
                     {
                         /* Parse routine might not have cleared this, do it */
-                        CurrentObject = NULL;
+                        Object = NULL;
                     }
-                    else if (!CurrentObject)
+                    else if (!Object)
                     {
                         /* Modify status to reflect failure inside Ob */
                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
                     }
 
                     /* We're done, return the status and object */
-                    *ReturnedObject = CurrentObject;
+                    *FoundObject = Object;
                     ObDereferenceObject(RootDirectory);
                     return Status;
                 }
@@ -269,11 +407,26 @@ ObFindObject(IN HANDLE RootHandle,
                 {
                     /* Reparsed to the root directory, so start over */
                     ObDereferenceObject(RootDirectory);
-                    RootDirectory = NameSpaceRoot;
+                    RootDirectory = ObpRootDirectoryObject;
 
                     /* Don't use this anymore, since we're starting at root */
                     RootHandle = NULL;
-                    break;
+                    goto ParseFromRoot;
+                }
+                else if (--MaxReparse)
+                {
+                    /* Try reparsing again */
+                    continue;
+                }
+                else
+                {
+                    /* Reparsed too many times */
+                    ObDereferenceObject(RootDirectory);
+
+                    /* Return the object and normalized status */
+                    *FoundObject = Object;
+                    if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                    return Status;
                 }
             }
         }
@@ -284,15 +437,18 @@ ObFindObject(IN HANDLE RootHandle,
                                                 0,
                                                 ObjectType,
                                                 AccessMode);
-            if (NT_SUCCESS(Status)) *ReturnedObject = RootDirectory;
+            if (NT_SUCCESS(Status)) Object = RootDirectory;
+
+            /* Remove the first reference we added and return the object */
             ObDereferenceObject(RootDirectory);
+            *FoundObject = Object;
             return Status;
         }
     }
     else
     {
         /* We did not get a Root Directory, so use the root */
-        RootDirectory = NameSpaceRoot;
+        RootDirectory = ObpRootDirectoryObject;
 
         /* It must start with a path separator */
         if (!(ObjectName->Length) ||
@@ -310,14 +466,14 @@ ObFindObject(IN HANDLE RootHandle,
             if (!RootDirectory)
             {
                 /* This must be the first time we're creating it... right? */
-                if (ExpectedObject)
+                if (InsertObject)
                 {
                     /* Yes, so return it to ObInsert so that it can create it */
-                    Status = ObReferenceObjectByPointer(ExpectedObject,
+                    Status = ObReferenceObjectByPointer(InsertObject,
                                                         0,
                                                         ObjectType,
                                                         AccessMode);
-                    if (NT_SUCCESS(Status)) *ReturnedObject = ExpectedObject;
+                    if (NT_SUCCESS(Status)) *FoundObject = InsertObject;
                     return Status;
                 }
                 else
@@ -334,257 +490,478 @@ ObFindObject(IN HANDLE RootHandle,
                                                     0,
                                                     ObjectType,
                                                     AccessMode);
-                if (NT_SUCCESS(Status)) *ReturnedObject = RootDirectory;
+                if (NT_SUCCESS(Status)) *FoundObject = RootDirectory;
                 return Status;
             }
         }
+        else
+        {
+ParseFromRoot:
+            /* FIXME: Check if we have a device map */
+
+            /* Check if this is a possible DOS name */
+            if (!((ULONG_PTR)(ObjectName->Buffer) & 7))
+            {
+                /*
+                 * This could be one. Does it match the prefix?
+                 * Note that as an optimization, the match is done as 64-bit
+                 * compare since the prefix is "\??\" which is exactly 8 bytes.
+                 *
+                 * In the second branch, we test for "\??" which is also valid.
+                 * This time, we use a 32-bit compare followed by a Unicode
+                 * character compare (16-bit), since the sum is 6 bytes.
+                 */
+                if ((ObjectName->Length >= ObpDosDevicesShortName.Length) &&
+                    (*(PULONGLONG)(ObjectName->Buffer) ==
+                     ObpDosDevicesShortNamePrefix.Alignment.QuadPart))
+                {
+                    /* FIXME! */
+                }
+                else if ((ObjectName->Length == ObpDosDevicesShortName.Length -
+                                                sizeof(WCHAR)) &&
+                         (*(PULONG)(ObjectName->Buffer) ==
+                          ObpDosDevicesShortNameRoot.Alignment.LowPart) &&
+                         (*((PWCHAR)(ObjectName->Buffer) + 2) ==
+                          (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart)))
+                {
+                    /* FIXME! */
+                }
+            }
+        }
     }
 
-    /* Save the name */
-ReparseNewDir:
-    RemainingPath = *ObjectName;
+    /* Check if we were reparsing a symbolic link */
+    if (!SymLink)
+    {
+        /* Allow reparse */
+        Reparse = TRUE;
+        MaxReparse = 30;
+    }
 
     /* Reparse */
-    while (TRUE)
+    while (Reparse)
     {
-        /* Check if we should use the Root Directory */
-        if (!InsideRoot)
-        {
-            /* Yes, use the root directory and remember that */
-            CurrentDirectory = RootDirectory;
-            InsideRoot = TRUE;
-        }
+        /* Get the name */
+        RemainingName = *ObjectName;
 
-        /* Check if the name starts with a path separator */
-        if ((RemainingPath.Length) &&
-            (RemainingPath.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
-        {
-            /* Skip the path separator */
-            RemainingPath.Buffer++;
-            RemainingPath.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
-        }
+        /* Disable reparsing again */
+        Reparse = FALSE;
 
-        /* Find the next Part Name */
-        PartName = RemainingPath;
-        while (RemainingPath.Length)
+        /* Start parse loop */
+        while (TRUE)
         {
-            /* Break if we found the \ ending */
-            if (RemainingPath.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
+            /* Clear object */
+            Object = NULL;
 
-            /* Move on */
-            RemainingPath.Buffer++;
-            RemainingPath.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
-        }
+            /* Check if the name starts with a path separator */
+            if ((RemainingName.Length) &&
+                (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
+            {
+                /* Skip the path separator */
+                RemainingName.Buffer++;
+                RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+            }
 
-        /* Get its size and make sure it's valid */
-        if (!(PartName.Length -= RemainingPath.Length))
-        {
-            Status = STATUS_OBJECT_NAME_INVALID;
-            break;
-        }
+            /* Find the next Part Name */
+            ComponentName = RemainingName;
+            while (RemainingName.Length)
+            {
+                /* Break if we found the \ ending */
+                if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
 
-        /* Do the look up */
-        Context->DirectoryLocked = TRUE;
-        Context->Directory = CurrentDirectory;
-        CurrentObject = ObpLookupEntryDirectory(CurrentDirectory,
-                                                &PartName,
-                                                Attributes,
-                                                FALSE,
-                                                Context);
-        if (!CurrentObject)
-        {
-            /* We didn't find it... do we still have a path? */
-            if (RemainingPath.Length)
+                /* Move on */
+                RemainingName.Buffer++;
+                RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+            }
+
+            /* Get its size and make sure it's valid */
+            ComponentName.Length -= RemainingName.Length;
+            if (!ComponentName.Length)
             {
-                /* Then tell the caller the path wasn't found */
-                Status = STATUS_OBJECT_PATH_NOT_FOUND;
+                /* Invalid size, fail */
+                Status = STATUS_OBJECT_NAME_INVALID;
                 break;
             }
-            else if (!ExpectedObject)
+
+            /* Check if we're in the root */
+            if (!Directory) Directory = RootDirectory;
+
+            /* Check if this is a user-mode call that needs to traverse */
+            if ((AccessCheckMode != KernelMode) &&
+                !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
             {
-                /* Otherwise, we have a path, but the name isn't valid */
-                Status = STATUS_OBJECT_NAME_NOT_FOUND;
-                break;
+                /* We shouldn't have referenced a directory yet */
+                ASSERT(ReferencedDirectory == NULL);
+
+                /* Reference the directory */
+                ObReferenceObject(Directory);
+                ReferencedDirectory = Directory;
+
+                /* Check if we have a parent directory */
+                if (ParentDirectory)
+                {
+                    /* Check for traverse access */
+                    if (!ObpCheckTraverseAccess(ParentDirectory,
+                                                DIRECTORY_TRAVERSE,
+                                                AccessState,
+                                                FALSE,
+                                                AccessCheckMode,
+                                                &Status))
+                    {
+                        /* We don't have it, fail */
+                        break;
+                    }
+                }
             }
 
-            /* Reference newly to be inserted object */
-            ObReferenceObject(ExpectedObject);
-            CurrentHeader = OBJECT_TO_OBJECT_HEADER(ExpectedObject);
+            /* Check if we don't have a remaining name yet */
+            if (!RemainingName.Length)
+            {
+                /* Check if we don't have a referenced directory yet */
+                if (!ReferencedDirectory)
+                {
+                    /* Reference it */
+                    ObReferenceObject(Directory);
+                    ReferencedDirectory = Directory;
+                }
+
+                /* Check if we are inserting an object */
+                if (InsertObject)
+                {
+                    /* Lock the directory */
+                    ObpAcquireDirectoryLockExclusive(Directory, LookupContext);
+                }
+            }
+
+            /* Do the lookup */
+            Object = ObpLookupEntryDirectory(Directory,
+                                             &ComponentName,
+                                             Attributes,
+                                             InsertObject ? FALSE : TRUE,
+                                             LookupContext);
+            if (!Object)
+            {
+                /* We didn't find it... do we still have a path? */
+                if (RemainingName.Length)
+                {
+                    /* Then tell the caller the path wasn't found */
+                    Status = STATUS_OBJECT_PATH_NOT_FOUND;
+                    break;
+                }
+                else if (!InsertObject)
+                {
+                    /* Otherwise, we have a path, but the name isn't valid */
+                    Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                    break;
+                }
+
+                /* Check create access for the object */
+                if (!ObCheckCreateObjectAccess(Directory,
+                                               ObjectType == ObDirectoryType ?
+                                               DIRECTORY_CREATE_SUBDIRECTORY :
+                                               DIRECTORY_CREATE_OBJECT,
+                                               AccessState,
+                                               &ComponentName,
+                                               FALSE,
+                                               AccessCheckMode,
+                                               &Status))
+                {
+                    /* We don't have create access, fail */
+                    break;
+                }
 
-            /* Create Object Name */
-            NewName = ExAllocatePoolWithTag(NonPagedPool,
-                                            PartName.MaximumLength,
-                                            OB_NAME_TAG);
-            ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(CurrentHeader);
+                /* Get the object header */
+                ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject);
+
+                /* FIXME: Check if this is a Section Object or Sym Link */
+                /* FIXME: If it is, then check if this isn't session 0 */
+                /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
+                /* FIXME: If privilege isn't there, check for unsecure name */
+                /* FIXME: If it isn't a known unsecure name, then fail */
+
+                /* Create Object Name */
+                NewName = ExAllocatePoolWithTag(PagedPool,
+                                                ComponentName.Length,
+                                                OB_NAME_TAG);
+                if (!(NewName) ||
+                    !(ObpInsertEntryDirectory(Directory,
+                                              LookupContext,
+                                              ObjectHeader)))
+                {
+                    /* Either couldn't allocate the name, or insert failed */
+                    if (NewName) ExFreePool(NewName);
 
-            /* Copy the Name */
-            RtlMoveMemory(NewName, PartName.Buffer, PartName.MaximumLength);
+                    /* Fail due to memory reasons */
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+                    break;
+                }
 
-            /* Free old name */
-            if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer);
+                /* Reference newly to be inserted object */
+                ObReferenceObject(InsertObject);
 
-            /* Write new one */
-            ObjectNameInfo->Name.Buffer = NewName;
-            ObjectNameInfo->Name.Length = PartName.Length;
-            ObjectNameInfo->Name.MaximumLength = PartName.MaximumLength;
+                /* Get the name information */
+                ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
 
-            /* Rereference the Directory and insert */
-            ObReferenceObject(CurrentDirectory);
-            ObpInsertEntryDirectory(CurrentDirectory, Context, CurrentHeader);
+                /* Reference the directory */
+                ObReferenceObject(Directory);
 
-            /* Return Status and the Expected Object */
-            Status = STATUS_SUCCESS;
-            CurrentObject = ExpectedObject;
+                /* Copy the Name */
+                RtlCopyMemory(NewName,
+                              ComponentName.Buffer,
+                              ComponentName.Length);
 
-            /* Get out of here */
-            break;
-        }
+                /* Check if we had an old name */
+                if (ObjectNameInfo->Name.Buffer)
+                {
+                    /* Free it */
+                    ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG );
+                }
 
-Reparse:
-        /* We found it, so now get its header */
-        CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
-
-        /* 
-         * Check for a parse Procedure, but don't bother to parse for an insert
-         * unless it's a Symbolic Link, in which case we MUST parse
-         */
-        ParseRoutine = CurrentHeader->Type->TypeInfo.ParseProcedure;
-        if (ParseRoutine &&
-            (!ExpectedObject || ParseRoutine == ObpParseSymbolicLink))
-        {
-            /* Use the Root Directory next time */
-            InsideRoot = FALSE;
-
-            /* Call the Parse Procedure */
-            Status = ParseRoutine(CurrentObject,
-                                  ObjectType,
-                                  AccessState,
-                                  AccessMode,
-                                  Attributes,
-                                  ObjectName,
-                                  &RemainingPath,
-                                  ParseContext,
-                                  SecurityQos,
-                                  &CurrentObject);
-
-            /* Check if we have to reparse */
-            if ((Status == STATUS_REPARSE) ||
-                (Status == STATUS_REPARSE_OBJECT))
+                /* Write new one */
+                ObjectNameInfo->Name.Buffer = NewName;
+                ObjectNameInfo->Name.Length = ComponentName.Length;
+                ObjectNameInfo->Name.MaximumLength = ComponentName.Length;
+
+                /* Return Status and the Expected Object */
+                Status = STATUS_SUCCESS;
+                Object = InsertObject;
+
+                /* Get out of here */
+                break;
+            }
+
+ReparseObject:
+            /* We found it, so now get its header */
+            ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
+
+            /*
+             * Check for a parse Procedure, but don't bother to parse for an insert
+             * unless it's a Symbolic Link, in which case we MUST parse
+             */
+            ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
+            if ((ParseRoutine) &&
+                (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink)))
             {
-                /* Start over from root if we got sent back there */
-                if ((Status == STATUS_REPARSE_OBJECT) ||
-                    (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
+                /* Use the Root Directory next time */
+                Directory = NULL;
+
+                /* Increment the pointer count */
+                InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
+
+                /* Cleanup from the first lookup */
+                ObpReleaseLookupContext(LookupContext);
+
+                /* Check if we have a referenced directory */
+                if (ReferencedDirectory)
                 {
-                    /* Check if we got a root directory */
-                    if (RootHandle)
-                    {
-                        /* Stop using it, because we have a new directory now */
-                        ObDereferenceObject(RootDirectory);
-                        RootHandle = NULL;
-                    }
+                    /* We do, dereference it */
+                    ObDereferenceObject(ReferencedDirectory);
+                    ReferencedDirectory = NULL;
+                }
 
-                    /* Start at Root */
-                    RootDirectory = NameSpaceRoot;
+                /* Check if we have a referenced parent directory */
+                if (ReferencedParentDirectory)
+                {
+                    /* We do, dereference it */
+                    ObDereferenceObject(ReferencedParentDirectory);
+                    ReferencedParentDirectory = NULL;
+                }
 
-                    /* Check for reparse status */
-                    if (Status == STATUS_REPARSE_OBJECT)
+                /* Call the Parse Procedure */
+                ObpCalloutStart(&CalloutIrql);
+                Status = ParseRoutine(Object,
+                                      ObjectType,
+                                      AccessState,
+                                      AccessCheckMode,
+                                      Attributes,
+                                      ObjectName,
+                                      &RemainingName,
+                                      ParseContext,
+                                      SecurityQos,
+                                      &Object);
+                ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
+
+                /* Remove our extra reference */
+                ObDereferenceObject(&ObjectHeader->Body);
+
+                /* Check if we have to reparse */
+                if ((Status == STATUS_REPARSE) ||
+                    (Status == STATUS_REPARSE_OBJECT))
+                {
+                    /* Reparse again */
+                    Reparse = TRUE;
+
+                    /* Start over from root if we got sent back there */
+                    if ((Status == STATUS_REPARSE_OBJECT) ||
+                        (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
                     {
-                        /* Did we actually get an object to which to reparse? */
-                        if (!CurrentObject)
+                        /* Check if we got a root directory */
+                        if (RootHandle)
+                        {
+                            /* Stop using it, because we have a new directory now */
+                            ObDereferenceObject(RootDirectory);
+                            RootHandle = NULL;
+                        }
+
+                        /* Start at Root */
+                        ParentDirectory = NULL;
+                        RootDirectory = ObpRootDirectoryObject;
+
+                        /* Check for reparse status */
+                        if (Status == STATUS_REPARSE_OBJECT)
                         {
-                            /* We didn't, so set a failure status */
-                            Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                            /* Don't reparse again */
+                            Reparse = FALSE;
+
+                            /* Did we actually get an object to which to reparse? */
+                            if (!Object)
+                            {
+                                /* We didn't, so set a failure status */
+                                Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                            }
+                            else
+                            {
+                                /* We did, so we're free to parse the new object */
+                                goto ReparseObject;
+                            }
                         }
                         else
                         {
-                            /* We did, so we're free to parse the new object */
-                            InsideRoot = TRUE;
-                            goto Reparse;
+                            /* This is a symbolic link */
+                            SymLink = TRUE;
+                            goto ParseFromRoot;
                         }
                     }
-
-                    /* Restart the search */
-                    goto ReparseNewDir;
+                    else if (RootDirectory == ObpRootDirectoryObject)
+                    {
+                        /* We got STATUS_REPARSE but are at the Root Directory */
+                        Object = NULL;
+                        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                        Reparse = FALSE;
+                    }
                 }
-                else if (RootDirectory == NameSpaceRoot)
+                else if (!NT_SUCCESS(Status))
                 {
-                    /* We got STATUS_REPARSE but are at the Root Directory */
-                    CurrentObject = NULL;
-                    Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                    /* Total failure */
+                    Object = NULL;
                 }
-            }
-            else if (!NT_SUCCESS(Status))
-            {
-                /* Total failure */
-                CurrentObject = NULL;
-            }
-            else if (!CurrentObject)
-            {
-                /* We didn't reparse but we didn't find the Object Either */
-                Status = STATUS_OBJECT_NAME_NOT_FOUND;
-            }
-
-            /* Break out of the loop */
-            break;
-        }
-        else
-        {
-            /* No parse routine...do we still have a remaining name? */
-            if (!RemainingPath.Length)
-            {
-                /* Are we creating an object? */
-                if (!ExpectedObject)
+                else if (!Object)
                 {
-                    /* We don't... reference the Object */
-                    Status = ObReferenceObjectByPointer(CurrentObject,
-                                                        0,
-                                                        ObjectType,
-                                                        AccessMode);
-                    if (!NT_SUCCESS(Status)) CurrentObject = NULL;
+                    /* We didn't reparse but we didn't find the Object Either */
+                    Status = STATUS_OBJECT_NAME_NOT_FOUND;
                 }
 
-                /* And get out of the reparse loop */
+                /* Break out of the loop */
                 break;
             }
             else
             {
-                /* We still have a name; check if this is a directory object */
-                if (CurrentHeader->Type == ObDirectoryType)
+                /* No parse routine...do we still have a remaining name? */
+                if (!RemainingName.Length)
                 {
-                    /* Restart from this directory */
-                    CurrentDirectory = CurrentObject;
+                    /* Are we creating an object? */
+                    if (!InsertObject)
+                    {
+                        /* Check if this is a user-mode call that needs to traverse */
+                        if ((AccessCheckMode != KernelMode) &&
+                            !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
+                        {
+                            /* Check if we can get it */
+                            if (!ObpCheckTraverseAccess(Directory,
+                                                        DIRECTORY_TRAVERSE,
+                                                        AccessState,
+                                                        FALSE,
+                                                        AccessCheckMode,
+                                                        &Status))
+                            {
+                                /* We don't have access, fail */
+                                Object = NULL;
+                                break;
+                            }
+                        }
+
+                        /* Reference the Object */
+                        Status = ObReferenceObjectByPointer(Object,
+                                                            0,
+                                                            ObjectType,
+                                                            AccessMode);
+                        if (!NT_SUCCESS(Status)) Object = NULL;
+                    }
+
+                    /* And get out of the reparse loop */
+                    break;
                 }
                 else
                 {
-                    /* We still have a name, but no parse routine for it */
-                    Status = STATUS_OBJECT_TYPE_MISMATCH;
-                    CurrentObject = NULL;
-                    break;
+                    /* We still have a name; check if this is a directory object */
+                    if (ObjectHeader->Type == ObDirectoryType)
+                    {
+                        /* Check if we have a referenced parent directory */
+                        if (ReferencedParentDirectory)
+                        {
+                            /* Dereference it */
+                            ObDereferenceObject(ReferencedParentDirectory);
+                        }
+
+                        /* Restart the lookup from this directory */
+                        ReferencedParentDirectory = ReferencedDirectory;
+                        ParentDirectory = Directory;
+                        Directory = Object;
+                        ReferencedDirectory = NULL;
+                    }
+                    else
+                    {
+                        /* We still have a name, but no parse routine for it */
+                        Status = STATUS_OBJECT_TYPE_MISMATCH;
+                        Object = NULL;
+                        break;
+                    }
                 }
             }
         }
     }
 
-    /* Write what we found, and if it's null, check if we got success */
-    if (!(*ReturnedObject = CurrentObject) && (NT_SUCCESS(Status)))
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
     {
-        /* Nothing found... but we have success. Correct the status code */
-        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        /* Cleanup after lookup */
+        ObpReleaseLookupContext(LookupContext);
     }
 
-    /* Check if we had a root directory */
-    if (RootHandle)
+    /* Check if we have a device map and dereference it if so */
+    //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
+
+    /* Check if we have a referenced directory and dereference it if so */
+    if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory);
+
+    /* Check if we have a referenced parent directory */
+    if (ReferencedParentDirectory)
     {
-        /* Dereference it */
-        ObDereferenceObject(RootDirectory);
+        /* We do, dereference it */
+        ObDereferenceObject(ReferencedParentDirectory);
     }
 
+    /* Set the found object and check if we got one */
+    *FoundObject = Object;
+    if (!Object)
+    {
+        /* Nothing was found. Did we reparse or get success? */
+        if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status)))
+        {
+            /* Set correct failure */
+            Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        }
+    }
+
+    /* Check if we had a root directory */
+    if (RootHandle) ObDereferenceObject(RootDirectory);
+
     /* Return status to caller */
     OBTRACE(OB_NAMESPACE_DEBUG,
             "%s - Found Object: %p. Expected: %p\n",
             __FUNCTION__,
-            *ReturnedObject,
-            ExpectedObject);
+            *FoundObject,
+            InsertObject);
     return Status;
 }
 
@@ -592,9 +969,9 @@ Reparse:
 
 NTSTATUS
 NTAPI
-ObQueryNameString(IN  PVOID Object,
+ObQueryNameString(IN PVOID Object,
                   OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
-                  IN  ULONG Length,
+                  IN ULONG Length,
                   OUT PULONG ReturnLength)
 {
     POBJECT_HEADER_NAME_INFO LocalInfo;
@@ -602,6 +979,7 @@ ObQueryNameString(IN  PVOID Object,
     POBJECT_DIRECTORY ParentDirectory;
     ULONG NameSize;
     PWCH ObjectName;
+    BOOLEAN ObjectIsNamed;
 
     /* Get the Kernel Meta-Structures */
     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
@@ -611,8 +989,9 @@ ObQueryNameString(IN  PVOID Object,
     if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
     {
         /* Call the procedure */
+        ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0));
         return ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
-                                                               TRUE, //fixme
+                                                               ObjectIsNamed,
                                                                ObjectNameInfo,
                                                                Length,
                                                                ReturnLength,
@@ -640,7 +1019,7 @@ ObQueryNameString(IN  PVOID Object,
      * enough right at the beginning, not work our way through
      * and find out at the end
      */
-    if (Object == NameSpaceRoot)
+    if (Object == ObpRootDirectoryObject)
     {
         /* Size of the '\' string */
         NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
@@ -652,7 +1031,7 @@ ObQueryNameString(IN  PVOID Object,
         NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
 
         /* Loop inside the directory to get the top-most one (meaning root) */
-        while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
+        while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
         {
             /* Get the Name Information */
             LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
@@ -695,7 +1074,7 @@ ObQueryNameString(IN  PVOID Object,
     *--ObjectName = UNICODE_NULL;
 
     /* Check if the object is actually the Root directory */
-    if (Object == NameSpaceRoot)
+    if (Object == ObpRootDirectoryObject)
     {
         /* This is already the Root Directory, return "\\" */
         *--ObjectName = OBJ_NAME_PATH_SEPARATOR;
@@ -710,13 +1089,13 @@ ObQueryNameString(IN  PVOID Object,
         /* Start by adding the Object's Name */
         ObjectName = (PWCH)((ULONG_PTR)ObjectName -
                             LocalInfo->Name.Length);
-        RtlMoveMemory(ObjectName,
+        RtlCopyMemory(ObjectName,
                       LocalInfo->Name.Buffer,
                       LocalInfo->Name.Length);
 
         /* Now parse the Parent directories until we reach the top */
         ParentDirectory = LocalInfo->Directory;
-        while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
+        while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
         {
             /* Get the name information */
             LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
@@ -731,7 +1110,7 @@ ObQueryNameString(IN  PVOID Object,
                 /* Add the name */
                 ObjectName = (PWCH)((ULONG_PTR)ObjectName -
                                     LocalInfo->Name.Length);
-                RtlMoveMemory(ObjectName,
+                RtlCopyMemory(ObjectName,
                               LocalInfo->Name.Buffer,
                               LocalInfo->Name.Length);
 
@@ -741,7 +1120,6 @@ ObQueryNameString(IN  PVOID Object,
             else
             {
                 /* Directory without a name, we add "..." */
-                DPRINT("Nameless Directory\n");
                 ObjectName -= sizeof(L"...");
                 ObjectName = L"...";
                 break;
@@ -777,7 +1155,7 @@ ObQueryDeviceMapInformation(IN PEPROCESS Process,
 
     /* Make a copy */
     DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
-    RtlMoveMemory(DeviceMapInfo->Query.DriveType,
+    RtlCopyMemory(DeviceMapInfo->Query.DriveType,
                   ObSystemDeviceMap->DriveType,
                   sizeof(ObSystemDeviceMap->DriveType));