/*
* 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)
#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
-ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
- PUNICODE_STRING ObjectName,
- PVOID* ReturnedObject,
- PUNICODE_STRING RemainingPath,
- POBJECT_TYPE ObjectType,
- POBP_LOOKUP_CONTEXT Context,
- IN PACCESS_STATE AccessState,
- IN PVOID ParseContext)
+ObpCreateDosDevicesDirectory(VOID)
{
- PVOID NextObject;
- PVOID CurrentObject;
- PVOID RootObject;
- POBJECT_HEADER CurrentHeader;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING Name, LinkName;
+ HANDLE Handle, SymHandle;
NTSTATUS Status;
- PWSTR current;
- UNICODE_STRING PathString;
- ULONG Attributes;
- UNICODE_STRING CurrentUs;
- PAGED_CODE();
+ /* 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);
- DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, "
- "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath);
+ /* 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);
- RtlInitUnicodeString (RemainingPath, NULL);
+ /* 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;
+}
- if (ObjectCreateInfo->RootDirectory == NULL)
+VOID
+NTAPI
+ObDereferenceDeviceMap(IN PEPROCESS Process)
+{
+ //KIRQL OldIrql;
+ PDEVICE_MAP DeviceMap = Process->DeviceMap;
+
+ /* FIXME: We don't use Process Devicemaps yet */
+ if (DeviceMap)
{
- ObReferenceObjectByPointer(NameSpaceRoot,
- DIRECTORY_TRAVERSE,
- NULL,
- ObjectCreateInfo->ProbeMode);
- CurrentObject = NameSpaceRoot;
+ /* FIXME: Acquire the DeviceMap Spinlock */
+ // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
+
+ /* Delete the device map link and dereference it */
+ Process->DeviceMap = NULL;
+ if (--DeviceMap->ReferenceCount)
+ {
+ /* Nobody is referencing it anymore, unlink the DOS directory */
+ DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
+
+ /* FIXME: Release the DeviceMap Spinlock */
+ // KeReleasepinLock(DeviceMap->Lock, OldIrql);
+
+ /* Dereference the DOS Devices Directory and free the Device Map */
+ ObDereferenceObject(DeviceMap->DosDevicesDirectory);
+ ExFreePool(DeviceMap);
+ }
+ else
+ {
+ /* FIXME: Release the DeviceMap Spinlock */
+ // KeReleasepinLock(DeviceMap->Lock, OldIrql);
+ }
}
- else
+}
+
+VOID
+NTAPI
+ObInheritDeviceMap(IN PEPROCESS Parent,
+ IN PEPROCESS Process)
+{
+ /* FIXME: Devicemap Support */
+}
+
+/*++
+* @name ObpDeleteNameCheck
+*
+* The ObpDeleteNameCheck routine checks if a named object should be
+* removed from the object directory namespace.
+*
+* @param Object
+* Pointer to the object to check for possible removal.
+*
+* @return None.
+*
+* @remarks An object is removed if the following 4 criteria are met:
+* 1) The object has 0 handles open
+* 2) The object is in the directory namespace and has a name
+* 3) The object is not permanent
+*
+*--*/
+VOID
+NTAPI
+ObpDeleteNameCheck(IN PVOID Object)
+{
+ POBJECT_HEADER ObjectHeader;
+ OBP_LOOKUP_CONTEXT Context;
+ POBJECT_HEADER_NAME_INFO ObjectNameInfo;
+ POBJECT_TYPE ObjectType;
+ PVOID Directory = NULL;
+
+ /* Get object structures */
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
+ ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
+ ObjectType = ObjectHeader->Type;
+
+ /*
+ * Check if the handle count is 0, if the object is named,
+ * and if the object isn't a permanent object.
+ */
+ if (!(ObjectHeader->HandleCount) &&
+ (ObjectNameInfo) &&
+ (ObjectNameInfo->Name.Length) &&
+ (ObjectNameInfo->Directory) &&
+ !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
{
- Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory,
- 0,
- NULL,
- ObjectCreateInfo->ProbeMode,
- &CurrentObject,
- NULL);
- if (!NT_SUCCESS(Status))
+ /* 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)
{
- return Status;
+ /* Lock the object */
+ ObpAcquireObjectLock(ObjectHeader);
+
+ /* Make sure we can still delete the object */
+ if (!(ObjectHeader->HandleCount) &&
+ !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
+ {
+ /* First delete it from the directory */
+ ObpDeleteEntryDirectory(&Context);
+
+ /* 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;
+ }
+
+ /* Release the lock */
+ ObpReleaseObjectLock(ObjectHeader);
}
- }
- if (ObjectName->Length == 0 ||
- ObjectName->Buffer[0] == UNICODE_NULL)
+ /* 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 first remove the extra reference we had added */
+ ObpDereferenceNameInfo(ObjectNameInfo);
+
+ /* Now dereference the object as well */
+ ObDereferenceObject(Object);
+ }
+ }
+ else
{
- *ReturnedObject = CurrentObject;
- return STATUS_SUCCESS;
+ /* Remove the reference we added */
+ ObpDereferenceNameInfo(ObjectNameInfo);
}
+}
- if (ObjectCreateInfo->RootDirectory == NULL &&
- ObjectName->Buffer[0] != L'\\')
+NTSTATUS
+NTAPI
+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 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();
+ OBTRACE(OB_NAMESPACE_DEBUG,
+ "%s - Finding Object: %wZ. Expecting: %p\n",
+ __FUNCTION__,
+ ObjectName,
+ InsertObject);
+
+ /* Initialize starting state */
+ ObpInitializeLookupContext(LookupContext);
+ *FoundObject = NULL;
+ Status = STATUS_SUCCESS;
+ Object = NULL;
+
+ /* Check if case-insensitivity is checked */
+ if (ObpCaseInsensitive)
{
- ObDereferenceObject (CurrentObject);
- DPRINT1("failed\n");
- return STATUS_UNSUCCESSFUL;
+ /* Check if the object type requests this */
+ if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive))
+ {
+ /* Add the flag to disable case sensitivity */
+ Attributes |= OBJ_CASE_INSENSITIVE;
+ }
}
- /* Create a zero-terminated copy of the object name */
- PathString.Length = ObjectName->Length;
- PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR);
- PathString.Buffer = ExAllocatePool (NonPagedPool,
- PathString.MaximumLength);
- if (PathString.Buffer == NULL)
+ /* 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)
{
- ObDereferenceObject (CurrentObject);
- return STATUS_INSUFFICIENT_RESOURCES;
+ /* We did. Reference it */
+ Status = ObReferenceObjectByHandle(RootHandle,
+ 0,
+ NULL,
+ AccessMode,
+ (PVOID*)&RootDirectory,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Get the header */
+ 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) &&
+ (ObjectHeader->Type != IoFileObjectType))
+ {
+ /* The syntax is bad, so fail this request */
+ ObDereferenceObject(RootDirectory);
+ return STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+
+ /* Don't parse a Directory */
+ if (ObjectHeader->Type != ObDirectoryType)
+ {
+ /* Make sure the Object Type has a parse routine */
+ ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
+ if (!ParseRoutine)
+ {
+ /* We can't parse a name if we don't have a parse routine */
+ ObDereferenceObject(RootDirectory);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ /* Set default parse count */
+ MaxReparse = 30;
+
+ /* Now parse */
+ while (TRUE)
+ {
+ /* Start with the full name */
+ RemainingName = *ObjectName;
+
+ /* Call the Parse Procedure */
+ ObpCalloutStart(&CalloutIrql);
+ Status = ParseRoutine(RootDirectory,
+ ObjectType,
+ AccessState,
+ AccessCheckMode,
+ Attributes,
+ ObjectName,
+ &RemainingName,
+ ParseContext,
+ SecurityQos,
+ &Object);
+ ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
+
+ /* Check for success or failure, so not reparse */
+ if ((Status != STATUS_REPARSE) &&
+ (Status != STATUS_REPARSE_OBJECT))
+ {
+ /* Check for failure */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Parse routine might not have cleared this, do it */
+ Object = NULL;
+ }
+ else if (!Object)
+ {
+ /* Modify status to reflect failure inside Ob */
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* We're done, return the status and object */
+ *FoundObject = Object;
+ ObDereferenceObject(RootDirectory);
+ return Status;
+ }
+ else if ((!ObjectName->Length) ||
+ (!ObjectName->Buffer) ||
+ (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
+ {
+ /* Reparsed to the root directory, so start over */
+ ObDereferenceObject(RootDirectory);
+ RootDirectory = ObpRootDirectoryObject;
+
+ /* Don't use this anymore, since we're starting at root */
+ RootHandle = NULL;
+ 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;
+ }
+ }
+ }
+ else if (!(ObjectName->Length) || !(ObjectName->Buffer))
+ {
+ /* Just return the Root Directory if we didn't get a name*/
+ Status = ObReferenceObjectByPointer(RootDirectory,
+ 0,
+ ObjectType,
+ AccessMode);
+ 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 = ObpRootDirectoryObject;
- RtlCopyMemory (PathString.Buffer,
- ObjectName->Buffer,
- ObjectName->Length);
- PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL;
+ /* It must start with a path separator */
+ if (!(ObjectName->Length) ||
+ !(ObjectName->Buffer) ||
+ (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR))
+ {
+ /* This name is invalid, so fail */
+ return STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
- current = PathString.Buffer;
+ /* Check if the name is only the path separator */
+ if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR))
+ {
+ /* So the caller only wants the root directory; do we have one? */
+ if (!RootDirectory)
+ {
+ /* This must be the first time we're creating it... right? */
+ if (InsertObject)
+ {
+ /* Yes, so return it to ObInsert so that it can create it */
+ Status = ObReferenceObjectByPointer(InsertObject,
+ 0,
+ ObjectType,
+ AccessMode);
+ if (NT_SUCCESS(Status)) *FoundObject = InsertObject;
+ return Status;
+ }
+ else
+ {
+ /* This should never really happen */
+ ASSERT(FALSE);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ /* We do have the root directory, so just return it */
+ Status = ObReferenceObjectByPointer(RootDirectory,
+ 0,
+ ObjectType,
+ AccessMode);
+ if (NT_SUCCESS(Status)) *FoundObject = RootDirectory;
+ return Status;
+ }
+ }
+ else
+ {
+ParseFromRoot:
+ /* FIXME: Check if we have a device map */
- RootObject = CurrentObject;
- Attributes = ObjectCreateInfo->Attributes;
- if (ObjectType == ObSymbolicLinkType)
- Attributes |= OBJ_OPENLINK;
+ /* 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! */
+ }
+ }
+ }
+ }
- while (TRUE)
+ /* Check if we were reparsing a symbolic link */
+ if (!SymLink)
{
- CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
+ /* Allow reparse */
+ Reparse = TRUE;
+ MaxReparse = 30;
+ }
- /* Loop as long as we're dealing with a directory */
- while (CurrentHeader->Type == ObDirectoryType)
+ /* Reparse */
+ while (Reparse)
+ {
+ /* Get the name */
+ RemainingName = *ObjectName;
+
+ /* Disable reparsing again */
+ Reparse = FALSE;
+
+ /* Start parse loop */
+ while (TRUE)
{
- PWSTR Start, End;
- PVOID FoundObject;
- UNICODE_STRING StartUs;
- NextObject = NULL;
+ /* Clear object */
+ Object = NULL;
+
+ /* 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);
+ }
+
+ /* 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;
- if (!current) goto Next;
+ /* Move on */
+ RemainingName.Buffer++;
+ RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+ }
- Start = current;
- if (*Start == L'\\') Start++;
+ /* Get its size and make sure it's valid */
+ ComponentName.Length -= RemainingName.Length;
+ if (!ComponentName.Length)
+ {
+ /* Invalid size, fail */
+ Status = STATUS_OBJECT_NAME_INVALID;
+ break;
+ }
- End = wcschr(Start, L'\\');
- if (End != NULL) *End = 0;
+ /* Check if we're in the root */
+ if (!Directory) Directory = RootDirectory;
- RtlInitUnicodeString(&StartUs, Start);
- Context->DirectoryLocked = TRUE;
- Context->Directory = CurrentObject;
- FoundObject = ObpLookupEntryDirectory(CurrentObject, &StartUs, Attributes, FALSE, Context);
- if (FoundObject == NULL)
+ /* Check if this is a user-mode call that needs to traverse */
+ if ((AccessCheckMode != KernelMode) &&
+ !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
{
- if (End != NULL)
+ /* 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)
{
- *End = L'\\';
+ /* Check for traverse access */
+ if (!ObpCheckTraverseAccess(ParentDirectory,
+ DIRECTORY_TRAVERSE,
+ AccessState,
+ FALSE,
+ AccessCheckMode,
+ &Status))
+ {
+ /* We don't have it, fail */
+ break;
+ }
}
- goto Next;
}
- ObReferenceObjectByPointer(FoundObject,
- STANDARD_RIGHTS_REQUIRED,
- NULL,
- UserMode);
- if (End != NULL)
+ /* Check if we don't have a remaining name yet */
+ if (!RemainingName.Length)
{
- *End = L'\\';
- current = End;
+ /* 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);
+ }
}
- else
+
+ /* Do the lookup */
+ Object = ObpLookupEntryDirectory(Directory,
+ &ComponentName,
+ Attributes,
+ InsertObject ? FALSE : TRUE,
+ LookupContext);
+ if (!Object)
{
- current = NULL;
+ /* 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;
+ }
+
+ /* 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);
+
+ /* Fail due to memory reasons */
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Reference newly to be inserted object */
+ ObReferenceObject(InsertObject);
+
+ /* Get the name information */
+ ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+
+ /* Reference the directory */
+ ObReferenceObject(Directory);
+
+ /* Copy the Name */
+ RtlCopyMemory(NewName,
+ ComponentName.Buffer,
+ ComponentName.Length);
+
+ /* Check if we had an old name */
+ if (ObjectNameInfo->Name.Buffer)
+ {
+ /* Free it */
+ ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG );
+ }
+
+ /* 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;
}
- NextObject = FoundObject;
+ReparseObject:
+ /* We found it, so now get its header */
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
-Next:
- if (NextObject == NULL)
+ /*
+ * 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)))
{
+ /* 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)
+ {
+ /* We do, dereference it */
+ ObDereferenceObject(ReferencedDirectory);
+ ReferencedDirectory = NULL;
+ }
+
+ /* Check if we have a referenced parent directory */
+ if (ReferencedParentDirectory)
+ {
+ /* We do, dereference it */
+ ObDereferenceObject(ReferencedParentDirectory);
+ ReferencedParentDirectory = NULL;
+ }
+
+ /* 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))
+ {
+ /* 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)
+ {
+ /* 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
+ {
+ /* This is a symbolic link */
+ SymLink = TRUE;
+ goto ParseFromRoot;
+ }
+ }
+ 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 (!NT_SUCCESS(Status))
+ {
+ /* Total failure */
+ Object = NULL;
+ }
+ else if (!Object)
+ {
+ /* We didn't reparse but we didn't find the Object Either */
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* Break out of the loop */
break;
}
- ObDereferenceObject(CurrentObject);
- CurrentObject = NextObject;
- CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
- }
+ else
+ {
+ /* No parse routine...do we still have a remaining name? */
+ if (!RemainingName.Length)
+ {
+ /* 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;
+ }
+ }
- if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL)
- {
- DPRINT("Current object can't parse\n");
- break;
- }
+ /* Reference the Object */
+ Status = ObReferenceObjectByPointer(Object,
+ 0,
+ ObjectType,
+ AccessMode);
+ if (!NT_SUCCESS(Status)) Object = NULL;
+ }
- RtlInitUnicodeString(&CurrentUs, current);
- Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject,
- CurrentHeader->Type,
- AccessState,
- ExGetPreviousMode(), // fixme: should be a parameter, since caller decides.
- Attributes,
- &PathString,
- &CurrentUs,
- ParseContext,
- NULL, // fixme: where do we get this from? captured OBP?
- &NextObject);
- current = CurrentUs.Buffer;
- if (Status == STATUS_REPARSE)
- {
- /* reparse the object path */
- NextObject = NameSpaceRoot;
- current = PathString.Buffer;
-
- ObReferenceObjectByPointer(NextObject,
- DIRECTORY_TRAVERSE,
- NULL,
- ObjectCreateInfo->ProbeMode);
+ /* And get out of the reparse loop */
+ break;
+ }
+ else
+ {
+ /* 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;
+ }
+ }
+ }
}
+ }
+ /* Check if we failed */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Cleanup after lookup */
+ ObpReleaseLookupContext(LookupContext);
+ }
- if (NextObject == NULL)
- {
- break;
- }
- ObDereferenceObject(CurrentObject);
- CurrentObject = NextObject;
+ /* 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)
+ {
+ /* We do, dereference it */
+ ObDereferenceObject(ReferencedParentDirectory);
}
- if (current)
+ /* Set the found object and check if we got one */
+ *FoundObject = Object;
+ if (!Object)
{
- RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool);
+ /* 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;
+ }
}
- RtlFreeUnicodeString (&PathString);
- *ReturnedObject = CurrentObject;
+ /* Check if we had a root directory */
+ if (RootHandle) ObDereferenceObject(RootDirectory);
- return STATUS_SUCCESS;
+ /* Return status to caller */
+ OBTRACE(OB_NAMESPACE_DEBUG,
+ "%s - Found Object: %p. Expected: %p\n",
+ __FUNCTION__,
+ *FoundObject,
+ InsertObject);
+ return Status;
}
/* PUBLIC FUNCTIONS *********************************************************/
-NTSTATUS
-STDCALL
-ObQueryNameString(IN PVOID Object,
+NTSTATUS
+NTAPI
+ObQueryNameString(IN PVOID Object,
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
- IN ULONG Length,
+ IN ULONG Length,
OUT PULONG ReturnLength)
{
POBJECT_HEADER_NAME_INFO LocalInfo;
POBJECT_DIRECTORY ParentDirectory;
ULONG NameSize;
PWCH ObjectName;
- NTSTATUS Status;
-
- DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo);
+ BOOLEAN ObjectIsNamed;
/* Get the Kernel Meta-Structures */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
/* Check if a Query Name Procedure is available */
- if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
- {
+ if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
+ {
/* Call the procedure */
- DPRINT("Calling Object's Procedure\n");
- Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
- TRUE, //fixme
- ObjectNameInfo,
- Length,
- ReturnLength);
-
- /* Return the status */
- return Status;
+ ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0));
+ return ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
+ ObjectIsNamed,
+ ObjectNameInfo,
+ Length,
+ ReturnLength,
+ KernelMode);
}
/* Check if the object doesn't even have a name */
- if (!LocalInfo || !LocalInfo->Name.Buffer)
+ if (!(LocalInfo) || !(LocalInfo->Name.Buffer))
{
/* We're returning the name structure */
- DPRINT("Nameless Object\n");
*ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
/* Check if we were given enough space */
- if (*ReturnLength > Length)
- {
- DPRINT1("Not enough buffer space\n");
- return STATUS_INFO_LENGTH_MISMATCH;
- }
+ if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
/* Return an empty buffer */
- ObjectNameInfo->Name.Length = 0;
- ObjectNameInfo->Name.MaximumLength = 0;
- ObjectNameInfo->Name.Buffer = NULL;
-
+ RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
return STATUS_SUCCESS;
}
- /*
+ /*
* Find the size needed for the name. We won't do
* this during the Name Creation loop because we want
* to let the caller know that the buffer isn't big
* 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 */
- DPRINT("Object is Root\n");
NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
- }
- else
+ }
+ else
{
/* Get the Object Directory and add name of Object */
ParentDirectory = LocalInfo->Directory;
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(OBJECT_TO_OBJECT_HEADER(ParentDirectory));
+ LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
+ OBJECT_TO_OBJECT_HEADER(ParentDirectory));
/* Add the size of the Directory Name */
- if (LocalInfo && LocalInfo->Directory)
+ if (LocalInfo && LocalInfo->Directory)
{
/* Size of the '\' string + Directory Name */
- NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
+ NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) +
+ LocalInfo->Name.Length;
/* Move to next parent Directory */
ParentDirectory = LocalInfo->Directory;
- }
- else
+ }
+ else
{
/* Directory with no name. We append "...\" */
- DPRINT("Nameless Directory\n");
NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
break;
}
}
/* Finally, add the name of the structure and the null char */
- *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL);
- DPRINT("Final Length: %x\n", *ReturnLength);
+ *ReturnLength = NameSize +
+ sizeof(OBJECT_NAME_INFORMATION) +
+ sizeof(UNICODE_NULL);
/* Check if we were given enough space */
- if (*ReturnLength > Length)
- {
- DPRINT1("Not enough buffer space\n");
- return STATUS_INFO_LENGTH_MISMATCH;
- }
+ if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
- /*
+ /*
* Now we will actually create the name. We work backwards because
* it's easier to start off from the Name we have and walk up the
* parent directories. We use the same logic as Name Length calculation.
ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
*--ObjectName = UNICODE_NULL;
- if (Object == NameSpaceRoot)
+ /* Check if the object is actually the Root directory */
+ if (Object == ObpRootDirectoryObject)
{
/* This is already the Root Directory, return "\\" */
- DPRINT("Returning Root Dir\n");
*--ObjectName = OBJ_NAME_PATH_SEPARATOR;
ObjectNameInfo->Name.Length = (USHORT)NameSize;
- ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
+ ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
+ sizeof(UNICODE_NULL));
ObjectNameInfo->Name.Buffer = ObjectName;
-
return STATUS_SUCCESS;
- }
- else
+ }
+ else
{
/* Start by adding the Object's Name */
- ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
- RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
+ ObjectName = (PWCH)((ULONG_PTR)ObjectName -
+ LocalInfo->Name.Length);
+ 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(OBJECT_TO_OBJECT_HEADER(ParentDirectory));
+ LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
+ OBJECT_TO_OBJECT_HEADER(ParentDirectory));
/* Add the "\" */
*(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
/* Add the Parent Directory's Name */
- if (LocalInfo && LocalInfo->Name.Buffer)
+ if (LocalInfo && LocalInfo->Name.Buffer)
{
/* Add the name */
- ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
- RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
+ ObjectName = (PWCH)((ULONG_PTR)ObjectName -
+ LocalInfo->Name.Length);
+ RtlCopyMemory(ObjectName,
+ LocalInfo->Name.Buffer,
+ LocalInfo->Name.Length);
/* Move to next parent */
ParentDirectory = LocalInfo->Directory;
- }
- else
+ }
+ else
{
/* Directory without a name, we add "..." */
- DPRINT("Nameless Directory\n");
ObjectName -= sizeof(L"...");
ObjectName = L"...";
break;
/* Add Root Directory Name */
*(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
- DPRINT("Current Buffer: %S\n", ObjectName);
ObjectNameInfo->Name.Length = (USHORT)NameSize;
- ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
+ ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
+ sizeof(UNICODE_NULL));
ObjectNameInfo->Name.Buffer = ObjectName;
- DPRINT("Complete: %wZ\n", ObjectNameInfo);
}
+ /* Return success */
return STATUS_SUCCESS;
}
/* Make a copy */
DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
- RtlMoveMemory(DeviceMapInfo->Query.DriveType,
+ RtlCopyMemory(DeviceMapInfo->Query.DriveType,
ObSystemDeviceMap->DriveType,
sizeof(ObSystemDeviceMap->DriveType));