2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obname.c
5 * PURPOSE: Manages all functions related to the Object Manager name-
6 * space, such as finding objects or querying their names.
7 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 * Thomas Weidenmueller (w3seek@reactos.org)
12 /* INCLUDES ******************************************************************/
18 BOOLEAN ObpCaseInsensitive
= TRUE
;
19 POBJECT_DIRECTORY ObpRootDirectoryObject
;
20 POBJECT_DIRECTORY ObpTypeDirectoryObject
;
22 /* DOS Device Prefix \??\ and \?? */
23 ALIGNEDNAME ObpDosDevicesShortNamePrefix
= {{L
'\\',L
'?',L
'?',L
'\\'}};
24 ALIGNEDNAME ObpDosDevicesShortNameRoot
= {{L
'\\',L
'?',L
'?',L
'\0'}};
25 UNICODE_STRING ObpDosDevicesShortName
=
27 sizeof(ObpDosDevicesShortNamePrefix
),
28 sizeof(ObpDosDevicesShortNamePrefix
),
29 (PWSTR
)&ObpDosDevicesShortNamePrefix
32 /* PRIVATE FUNCTIONS *********************************************************/
36 ObpCreateDosDevicesDirectory(VOID
)
38 OBJECT_ATTRIBUTES ObjectAttributes
;
39 UNICODE_STRING Name
, LinkName
;
40 HANDLE Handle
, SymHandle
;
43 /* Create the '\??' directory */
44 RtlInitUnicodeString(&Name
, L
"\\??");
45 InitializeObjectAttributes(&ObjectAttributes
,
50 Status
= NtCreateDirectoryObject(&Handle
,
53 if (!NT_SUCCESS(Status
)) return FALSE
;
55 /* Initialize the GLOBALROOT path */
56 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
57 RtlInitUnicodeString(&Name
, L
"");
58 InitializeObjectAttributes(&ObjectAttributes
,
63 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
64 SYMBOLIC_LINK_ALL_ACCESS
,
67 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
69 /* Link \??\Global to \?? */
70 RtlInitUnicodeString(&LinkName
, L
"Global");
71 RtlInitUnicodeString(&Name
, L
"\\??");
72 InitializeObjectAttributes(&ObjectAttributes
,
77 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
78 SYMBOLIC_LINK_ALL_ACCESS
,
81 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
83 /* Close the directory handle */
85 if (!NT_SUCCESS(Status
)) return Status
;
87 /* Create link from '\DosDevices' to '\??' directory */
88 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
89 InitializeObjectAttributes(&ObjectAttributes
,
94 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
95 SYMBOLIC_LINK_ALL_ACCESS
,
98 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
100 /* FIXME: Hack Hack! */
101 ObSystemDeviceMap
= ExAllocatePoolWithTag(NonPagedPool
,
102 sizeof(*ObSystemDeviceMap
),
104 if (!ObSystemDeviceMap
) return STATUS_INSUFFICIENT_RESOURCES
;
105 RtlZeroMemory(ObSystemDeviceMap
, sizeof(*ObSystemDeviceMap
));
113 ObDereferenceDeviceMap(IN PEPROCESS Process
)
116 PDEVICE_MAP DeviceMap
= Process
->DeviceMap
;
118 /* FIXME: We don't use Process Devicemaps yet */
121 /* FIXME: Acquire the DeviceMap Spinlock */
122 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
124 /* Delete the device map link and dereference it */
125 Process
->DeviceMap
= NULL
;
126 if (--DeviceMap
->ReferenceCount
)
128 /* Nobody is referencing it anymore, unlink the DOS directory */
129 DeviceMap
->DosDevicesDirectory
->DeviceMap
= NULL
;
131 /* FIXME: Release the DeviceMap Spinlock */
132 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
134 /* Dereference the DOS Devices Directory and free the Device Map */
135 ObDereferenceObject(DeviceMap
->DosDevicesDirectory
);
136 ExFreePool(DeviceMap
);
140 /* FIXME: Release the DeviceMap Spinlock */
141 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
148 ObInheritDeviceMap(IN PEPROCESS Parent
,
149 IN PEPROCESS Process
)
151 /* FIXME: Devicemap Support */
155 * @name ObpDeleteNameCheck
157 * The ObpDeleteNameCheck routine checks if a named object should be
158 * removed from the object directory namespace.
161 * Pointer to the object to check for possible removal.
165 * @remarks An object is removed if the following 4 criteria are met:
166 * 1) The object has 0 handles open
167 * 2) The object is in the directory namespace and has a name
168 * 3) The object is not permanent
173 ObpDeleteNameCheck(IN PVOID Object
)
175 POBJECT_HEADER ObjectHeader
;
176 OBP_LOOKUP_CONTEXT Context
;
177 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
178 POBJECT_TYPE ObjectType
;
179 PVOID Directory
= NULL
;
181 /* Get object structures */
182 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
183 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
184 ObjectType
= ObjectHeader
->Type
;
187 * Check if the handle count is 0, if the object is named,
188 * and if the object isn't a permanent object.
190 if (!(ObjectHeader
->HandleCount
) &&
192 (ObjectNameInfo
->Name
.Length
) &&
193 (ObjectNameInfo
->Directory
) &&
194 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
196 /* Setup a lookup context */
197 ObpInitializeLookupContext(&Context
);
199 /* Lock the directory */
200 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
203 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
204 &ObjectNameInfo
->Name
,
210 /* Lock the object */
211 ObpAcquireObjectLock(ObjectHeader
);
213 /* Make sure we can still delete the object */
214 if (!(ObjectHeader
->HandleCount
) &&
215 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
217 /* First delete it from the directory */
218 ObpDeleteEntryDirectory(&Context
);
220 /* Check if this is a symbolic link */
221 if (ObjectType
== ObSymbolicLinkType
)
223 /* Remove internal name */
224 ObpDeleteSymbolicLinkName(Object
);
227 /* Check if the magic protection flag is set */
228 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
229 if ((ObjectNameInfo
) &&
230 (ObjectNameInfo
->QueryReferences
& 0x40000000))
232 /* Remove protection flag */
233 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
237 /* Get the directory */
238 Directory
= ObjectNameInfo
->Directory
;
241 /* Release the lock */
242 ObpReleaseObjectLock(ObjectHeader
);
245 /* Cleanup after lookup */
246 ObpReleaseLookupContext(&Context
);
248 /* Remove another query reference since we added one on top */
249 ObpDereferenceNameInfo(ObjectNameInfo
);
251 /* Check if we were inserted in a directory */
254 /* We were, so first remove the extra reference we had added */
255 ObpDereferenceNameInfo(ObjectNameInfo
);
257 /* Now dereference the object as well */
258 ObDereferenceObject(Object
);
263 /* Remove the reference we added */
264 ObpDereferenceNameInfo(ObjectNameInfo
);
270 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
271 IN PUNICODE_STRING ObjectName
,
273 IN POBJECT_TYPE ObjectType
,
274 IN KPROCESSOR_MODE AccessMode
,
275 IN OUT PVOID ParseContext
,
276 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
277 IN PVOID InsertObject OPTIONAL
,
278 IN OUT PACCESS_STATE AccessState
,
279 OUT POBP_LOOKUP_CONTEXT LookupContext
,
280 OUT PVOID
*FoundObject
)
283 POBJECT_HEADER ObjectHeader
;
284 UNICODE_STRING ComponentName
, RemainingName
;
285 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
286 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
287 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
289 OB_PARSE_METHOD ParseRoutine
;
291 KPROCESSOR_MODE AccessCheckMode
;
293 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
294 ULONG MaxReparse
= 30;
296 OBTRACE(OB_NAMESPACE_DEBUG
,
297 "%s - Finding Object: %wZ. Expecting: %p\n",
302 /* Initialize starting state */
303 ObpInitializeLookupContext(LookupContext
);
305 Status
= STATUS_SUCCESS
;
308 /* Check if case-insensitivity is checked */
309 if (ObpCaseInsensitive
)
311 /* Check if the object type requests this */
312 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
314 /* Add the flag to disable case sensitivity */
315 Attributes
|= OBJ_CASE_INSENSITIVE
;
319 /* Check if this is a access checks are being forced */
320 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
321 UserMode
: AccessMode
;
323 /* Check if we got a Root Directory */
326 /* We did. Reference it */
327 Status
= ObReferenceObjectByHandle(RootHandle
,
331 (PVOID
*)&RootDirectory
,
333 if (!NT_SUCCESS(Status
)) return Status
;
336 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
338 /* The name cannot start with a separator, unless this is a file */
339 if ((ObjectName
->Buffer
) &&
340 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
341 (ObjectHeader
->Type
!= IoFileObjectType
))
343 /* The syntax is bad, so fail this request */
344 ObDereferenceObject(RootDirectory
);
345 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
348 /* Don't parse a Directory */
349 if (ObjectHeader
->Type
!= ObDirectoryType
)
351 /* Make sure the Object Type has a parse routine */
352 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
355 /* We can't parse a name if we don't have a parse routine */
356 ObDereferenceObject(RootDirectory
);
357 return STATUS_INVALID_HANDLE
;
360 /* Set default parse count */
366 /* Start with the full name */
367 RemainingName
= *ObjectName
;
369 /* Call the Parse Procedure */
370 ObpCalloutStart(&CalloutIrql
);
371 Status
= ParseRoutine(RootDirectory
,
381 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
383 /* Check for success or failure, so not reparse */
384 if ((Status
!= STATUS_REPARSE
) &&
385 (Status
!= STATUS_REPARSE_OBJECT
))
387 /* Check for failure */
388 if (!NT_SUCCESS(Status
))
390 /* Parse routine might not have cleared this, do it */
395 /* Modify status to reflect failure inside Ob */
396 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
399 /* We're done, return the status and object */
400 *FoundObject
= Object
;
401 ObDereferenceObject(RootDirectory
);
404 else if ((!ObjectName
->Length
) ||
405 (!ObjectName
->Buffer
) ||
406 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
408 /* Reparsed to the root directory, so start over */
409 ObDereferenceObject(RootDirectory
);
410 RootDirectory
= ObpRootDirectoryObject
;
412 /* Don't use this anymore, since we're starting at root */
416 else if (--MaxReparse
)
418 /* Try reparsing again */
423 /* Reparsed too many times */
424 ObDereferenceObject(RootDirectory
);
426 /* Return the object and normalized status */
427 *FoundObject
= Object
;
428 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
433 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
435 /* Just return the Root Directory if we didn't get a name*/
436 Status
= ObReferenceObjectByPointer(RootDirectory
,
440 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
442 /* Remove the first reference we added and return the object */
443 ObDereferenceObject(RootDirectory
);
444 *FoundObject
= Object
;
450 /* We did not get a Root Directory, so use the root */
451 RootDirectory
= ObpRootDirectoryObject
;
453 /* It must start with a path separator */
454 if (!(ObjectName
->Length
) ||
455 !(ObjectName
->Buffer
) ||
456 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
458 /* This name is invalid, so fail */
459 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
462 /* Check if the name is only the path separator */
463 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
465 /* So the caller only wants the root directory; do we have one? */
468 /* This must be the first time we're creating it... right? */
471 /* Yes, so return it to ObInsert so that it can create it */
472 Status
= ObReferenceObjectByPointer(InsertObject
,
476 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
481 /* This should never really happen */
483 return STATUS_INVALID_PARAMETER
;
488 /* We do have the root directory, so just return it */
489 Status
= ObReferenceObjectByPointer(RootDirectory
,
493 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
500 /* FIXME: Check if we have a device map */
502 /* Check if this is a possible DOS name */
503 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
506 * This could be one. Does it match the prefix?
507 * Note that as an optimization, the match is done as 64-bit
508 * compare since the prefix is "\??\" which is exactly 8 bytes.
510 * In the second branch, we test for "\??" which is also valid.
511 * This time, we use a 32-bit compare followed by a Unicode
512 * character compare (16-bit), since the sum is 6 bytes.
514 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
515 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
516 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
520 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
522 (*(PULONG
)(ObjectName
->Buffer
) ==
523 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
524 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
525 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
533 /* Check if we were reparsing a symbolic link */
545 RemainingName
= *ObjectName
;
547 /* Disable reparsing again */
550 /* Start parse loop */
556 /* Check if the name starts with a path separator */
557 if ((RemainingName
.Length
) &&
558 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
560 /* Skip the path separator */
561 RemainingName
.Buffer
++;
562 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
565 /* Find the next Part Name */
566 ComponentName
= RemainingName
;
567 while (RemainingName
.Length
)
569 /* Break if we found the \ ending */
570 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
573 RemainingName
.Buffer
++;
574 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
577 /* Get its size and make sure it's valid */
578 ComponentName
.Length
-= RemainingName
.Length
;
579 if (!ComponentName
.Length
)
581 /* Invalid size, fail */
582 Status
= STATUS_OBJECT_NAME_INVALID
;
586 /* Check if we're in the root */
587 if (!Directory
) Directory
= RootDirectory
;
589 /* Check if this is a user-mode call that needs to traverse */
590 if ((AccessCheckMode
!= KernelMode
) &&
591 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
593 /* We shouldn't have referenced a directory yet */
594 ASSERT(ReferencedDirectory
== NULL
);
596 /* Reference the directory */
597 ObReferenceObject(Directory
);
598 ReferencedDirectory
= Directory
;
600 /* Check if we have a parent directory */
603 /* Check for traverse access */
604 if (!ObpCheckTraverseAccess(ParentDirectory
,
611 /* We don't have it, fail */
617 /* Check if we don't have a remaining name yet */
618 if (!RemainingName
.Length
)
620 /* Check if we don't have a referenced directory yet */
621 if (!ReferencedDirectory
)
624 ObReferenceObject(Directory
);
625 ReferencedDirectory
= Directory
;
628 /* Check if we are inserting an object */
631 /* Lock the directory */
632 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
637 Object
= ObpLookupEntryDirectory(Directory
,
640 InsertObject
? FALSE
: TRUE
,
644 /* We didn't find it... do we still have a path? */
645 if (RemainingName
.Length
)
647 /* Then tell the caller the path wasn't found */
648 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
651 else if (!InsertObject
)
653 /* Otherwise, we have a path, but the name isn't valid */
654 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
658 /* Check create access for the object */
659 if (!ObCheckCreateObjectAccess(Directory
,
660 ObjectType
== ObDirectoryType
?
661 DIRECTORY_CREATE_SUBDIRECTORY
:
662 DIRECTORY_CREATE_OBJECT
,
669 /* We don't have create access, fail */
673 /* Get the object header */
674 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
676 /* FIXME: Check if this is a Section Object or Sym Link */
677 /* FIXME: If it is, then check if this isn't session 0 */
678 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
679 /* FIXME: If privilege isn't there, check for unsecure name */
680 /* FIXME: If it isn't a known unsecure name, then fail */
682 /* Create Object Name */
683 NewName
= ExAllocatePoolWithTag(PagedPool
,
684 ComponentName
.Length
,
687 !(ObpInsertEntryDirectory(Directory
,
691 /* Either couldn't allocate the name, or insert failed */
692 if (NewName
) ExFreePool(NewName
);
694 /* Fail due to memory reasons */
695 Status
= STATUS_INSUFFICIENT_RESOURCES
;
699 /* Reference newly to be inserted object */
700 ObReferenceObject(InsertObject
);
702 /* Get the name information */
703 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
705 /* Reference the directory */
706 ObReferenceObject(Directory
);
709 RtlCopyMemory(NewName
,
710 ComponentName
.Buffer
,
711 ComponentName
.Length
);
713 /* Check if we had an old name */
714 if (ObjectNameInfo
->Name
.Buffer
)
717 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
721 ObjectNameInfo
->Name
.Buffer
= NewName
;
722 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
723 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
725 /* Return Status and the Expected Object */
726 Status
= STATUS_SUCCESS
;
727 Object
= InsertObject
;
729 /* Get out of here */
734 /* We found it, so now get its header */
735 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
738 * Check for a parse Procedure, but don't bother to parse for an insert
739 * unless it's a Symbolic Link, in which case we MUST parse
741 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
742 if ((ParseRoutine
) &&
743 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
745 /* Use the Root Directory next time */
748 /* Increment the pointer count */
749 InterlockedExchangeAdd(&ObjectHeader
->PointerCount
, 1);
751 /* Cleanup from the first lookup */
752 ObpReleaseLookupContext(LookupContext
);
754 /* Check if we have a referenced directory */
755 if (ReferencedDirectory
)
757 /* We do, dereference it */
758 ObDereferenceObject(ReferencedDirectory
);
759 ReferencedDirectory
= NULL
;
762 /* Check if we have a referenced parent directory */
763 if (ReferencedParentDirectory
)
765 /* We do, dereference it */
766 ObDereferenceObject(ReferencedParentDirectory
);
767 ReferencedParentDirectory
= NULL
;
770 /* Call the Parse Procedure */
771 ObpCalloutStart(&CalloutIrql
);
772 Status
= ParseRoutine(Object
,
782 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
784 /* Remove our extra reference */
785 ObDereferenceObject(&ObjectHeader
->Body
);
787 /* Check if we have to reparse */
788 if ((Status
== STATUS_REPARSE
) ||
789 (Status
== STATUS_REPARSE_OBJECT
))
794 /* Start over from root if we got sent back there */
795 if ((Status
== STATUS_REPARSE_OBJECT
) ||
796 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
798 /* Check if we got a root directory */
801 /* Stop using it, because we have a new directory now */
802 ObDereferenceObject(RootDirectory
);
807 ParentDirectory
= NULL
;
808 RootDirectory
= ObpRootDirectoryObject
;
810 /* Check for reparse status */
811 if (Status
== STATUS_REPARSE_OBJECT
)
813 /* Don't reparse again */
816 /* Did we actually get an object to which to reparse? */
819 /* We didn't, so set a failure status */
820 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
824 /* We did, so we're free to parse the new object */
830 /* This is a symbolic link */
835 else if (RootDirectory
== ObpRootDirectoryObject
)
837 /* We got STATUS_REPARSE but are at the Root Directory */
839 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
843 else if (!NT_SUCCESS(Status
))
850 /* We didn't reparse but we didn't find the Object Either */
851 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
854 /* Break out of the loop */
859 /* No parse routine...do we still have a remaining name? */
860 if (!RemainingName
.Length
)
862 /* Are we creating an object? */
865 /* Check if this is a user-mode call that needs to traverse */
866 if ((AccessCheckMode
!= KernelMode
) &&
867 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
869 /* Check if we can get it */
870 if (!ObpCheckTraverseAccess(Directory
,
877 /* We don't have access, fail */
883 /* Reference the Object */
884 Status
= ObReferenceObjectByPointer(Object
,
888 if (!NT_SUCCESS(Status
)) Object
= NULL
;
891 /* And get out of the reparse loop */
896 /* We still have a name; check if this is a directory object */
897 if (ObjectHeader
->Type
== ObDirectoryType
)
899 /* Check if we have a referenced parent directory */
900 if (ReferencedParentDirectory
)
903 ObDereferenceObject(ReferencedParentDirectory
);
906 /* Restart the lookup from this directory */
907 ReferencedParentDirectory
= ReferencedDirectory
;
908 ParentDirectory
= Directory
;
910 ReferencedDirectory
= NULL
;
914 /* We still have a name, but no parse routine for it */
915 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
924 /* Check if we failed */
925 if (!NT_SUCCESS(Status
))
927 /* Cleanup after lookup */
928 ObpReleaseLookupContext(LookupContext
);
931 /* Check if we have a device map and dereference it if so */
932 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
934 /* Check if we have a referenced directory and dereference it if so */
935 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
937 /* Check if we have a referenced parent directory */
938 if (ReferencedParentDirectory
)
940 /* We do, dereference it */
941 ObDereferenceObject(ReferencedParentDirectory
);
944 /* Set the found object and check if we got one */
945 *FoundObject
= Object
;
948 /* Nothing was found. Did we reparse or get success? */
949 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
951 /* Set correct failure */
952 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
956 /* Check if we had a root directory */
957 if (RootHandle
) ObDereferenceObject(RootDirectory
);
959 /* Return status to caller */
960 OBTRACE(OB_NAMESPACE_DEBUG
,
961 "%s - Found Object: %p. Expected: %p\n",
968 /* PUBLIC FUNCTIONS *********************************************************/
972 ObQueryNameString(IN PVOID Object
,
973 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
975 OUT PULONG ReturnLength
)
977 POBJECT_HEADER_NAME_INFO LocalInfo
;
978 POBJECT_HEADER ObjectHeader
;
979 POBJECT_DIRECTORY ParentDirectory
;
982 BOOLEAN ObjectIsNamed
;
984 /* Get the Kernel Meta-Structures */
985 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
986 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
988 /* Check if a Query Name Procedure is available */
989 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
991 /* Call the procedure */
992 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
993 return ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1001 /* Check if the object doesn't even have a name */
1002 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1004 /* We're returning the name structure */
1005 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1007 /* Check if we were given enough space */
1008 if (*ReturnLength
> Length
) return STATUS_INFO_LENGTH_MISMATCH
;
1010 /* Return an empty buffer */
1011 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1012 return STATUS_SUCCESS
;
1016 * Find the size needed for the name. We won't do
1017 * this during the Name Creation loop because we want
1018 * to let the caller know that the buffer isn't big
1019 * enough right at the beginning, not work our way through
1020 * and find out at the end
1022 if (Object
== ObpRootDirectoryObject
)
1024 /* Size of the '\' string */
1025 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1029 /* Get the Object Directory and add name of Object */
1030 ParentDirectory
= LocalInfo
->Directory
;
1031 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1033 /* Loop inside the directory to get the top-most one (meaning root) */
1034 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1036 /* Get the Name Information */
1037 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1038 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1040 /* Add the size of the Directory Name */
1041 if (LocalInfo
&& LocalInfo
->Directory
)
1043 /* Size of the '\' string + Directory Name */
1044 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1045 LocalInfo
->Name
.Length
;
1047 /* Move to next parent Directory */
1048 ParentDirectory
= LocalInfo
->Directory
;
1052 /* Directory with no name. We append "...\" */
1053 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1059 /* Finally, add the name of the structure and the null char */
1060 *ReturnLength
= NameSize
+
1061 sizeof(OBJECT_NAME_INFORMATION
) +
1062 sizeof(UNICODE_NULL
);
1064 /* Check if we were given enough space */
1065 if (*ReturnLength
> Length
) return STATUS_INFO_LENGTH_MISMATCH
;
1068 * Now we will actually create the name. We work backwards because
1069 * it's easier to start off from the Name we have and walk up the
1070 * parent directories. We use the same logic as Name Length calculation.
1072 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1073 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1074 *--ObjectName
= UNICODE_NULL
;
1076 /* Check if the object is actually the Root directory */
1077 if (Object
== ObpRootDirectoryObject
)
1079 /* This is already the Root Directory, return "\\" */
1080 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1081 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1082 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1083 sizeof(UNICODE_NULL
));
1084 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1085 return STATUS_SUCCESS
;
1089 /* Start by adding the Object's Name */
1090 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1091 LocalInfo
->Name
.Length
);
1092 RtlCopyMemory(ObjectName
,
1093 LocalInfo
->Name
.Buffer
,
1094 LocalInfo
->Name
.Length
);
1096 /* Now parse the Parent directories until we reach the top */
1097 ParentDirectory
= LocalInfo
->Directory
;
1098 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1100 /* Get the name information */
1101 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1102 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1105 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1107 /* Add the Parent Directory's Name */
1108 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1111 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1112 LocalInfo
->Name
.Length
);
1113 RtlCopyMemory(ObjectName
,
1114 LocalInfo
->Name
.Buffer
,
1115 LocalInfo
->Name
.Length
);
1117 /* Move to next parent */
1118 ParentDirectory
= LocalInfo
->Directory
;
1122 /* Directory without a name, we add "..." */
1123 ObjectName
-= sizeof(L
"...");
1124 ObjectName
= L
"...";
1129 /* Add Root Directory Name */
1130 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1131 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1132 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1133 sizeof(UNICODE_NULL
));
1134 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1137 /* Return success */
1138 return STATUS_SUCCESS
;
1143 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
1144 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
1149 * FIXME: This is an ugly hack for now, to always return the System Device Map
1150 * instead of returning the Process Device Map. Not important yet since we don't use it
1153 /* FIXME: Acquire the DeviceMap Spinlock */
1154 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
1157 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
1158 RtlCopyMemory(DeviceMapInfo
->Query
.DriveType
,
1159 ObSystemDeviceMap
->DriveType
,
1160 sizeof(ObSystemDeviceMap
->DriveType
));
1162 /* FIXME: Release the DeviceMap Spinlock */
1163 // KeReleasepinLock(DeviceMap->Lock, OldIrql);