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 *********************************************************/
37 ObpCreateDosDevicesDirectory(VOID
)
39 OBJECT_ATTRIBUTES ObjectAttributes
;
40 UNICODE_STRING Name
, LinkName
;
41 HANDLE Handle
, SymHandle
;
44 /* Create the '\??' directory */
45 RtlInitUnicodeString(&Name
, L
"\\??");
46 InitializeObjectAttributes(&ObjectAttributes
,
51 Status
= NtCreateDirectoryObject(&Handle
,
54 if (!NT_SUCCESS(Status
)) return FALSE
;
56 /* Initialize the GLOBALROOT path */
57 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
58 RtlInitUnicodeString(&Name
, L
"");
59 InitializeObjectAttributes(&ObjectAttributes
,
64 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
65 SYMBOLIC_LINK_ALL_ACCESS
,
68 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
70 /* Link \??\Global to \?? */
71 RtlInitUnicodeString(&LinkName
, L
"Global");
72 RtlInitUnicodeString(&Name
, L
"\\??");
73 InitializeObjectAttributes(&ObjectAttributes
,
78 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
79 SYMBOLIC_LINK_ALL_ACCESS
,
82 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
84 /* Close the directory handle */
86 if (!NT_SUCCESS(Status
)) return Status
;
88 /* Create link from '\DosDevices' to '\??' directory */
89 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
90 InitializeObjectAttributes(&ObjectAttributes
,
95 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
96 SYMBOLIC_LINK_ALL_ACCESS
,
99 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
101 /* FIXME: Hack Hack! */
102 ObSystemDeviceMap
= ExAllocatePoolWithTag(NonPagedPool
,
103 sizeof(*ObSystemDeviceMap
),
105 if (!ObSystemDeviceMap
) return STATUS_INSUFFICIENT_RESOURCES
;
106 RtlZeroMemory(ObSystemDeviceMap
, sizeof(*ObSystemDeviceMap
));
114 ObDereferenceDeviceMap(IN PEPROCESS Process
)
117 PDEVICE_MAP DeviceMap
= Process
->DeviceMap
;
119 /* FIXME: We don't use Process Devicemaps yet */
122 /* FIXME: Acquire the DeviceMap Spinlock */
123 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
125 /* Delete the device map link and dereference it */
126 Process
->DeviceMap
= NULL
;
127 if (--DeviceMap
->ReferenceCount
)
129 /* Nobody is referencing it anymore, unlink the DOS directory */
130 DeviceMap
->DosDevicesDirectory
->DeviceMap
= NULL
;
132 /* FIXME: Release the DeviceMap Spinlock */
133 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
135 /* Dereference the DOS Devices Directory and free the Device Map */
136 ObDereferenceObject(DeviceMap
->DosDevicesDirectory
);
137 ExFreePool(DeviceMap
);
141 /* FIXME: Release the DeviceMap Spinlock */
142 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
149 ObInheritDeviceMap(IN PEPROCESS Parent
,
150 IN PEPROCESS Process
)
152 /* FIXME: Devicemap Support */
156 * @name ObpDeleteNameCheck
158 * The ObpDeleteNameCheck routine checks if a named object should be
159 * removed from the object directory namespace.
162 * Pointer to the object to check for possible removal.
166 * @remarks An object is removed if the following 4 criteria are met:
167 * 1) The object has 0 handles open
168 * 2) The object is in the directory namespace and has a name
169 * 3) The object is not permanent
174 ObpDeleteNameCheck(IN PVOID Object
)
176 POBJECT_HEADER ObjectHeader
;
177 OBP_LOOKUP_CONTEXT Context
;
178 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
179 POBJECT_TYPE ObjectType
;
180 PVOID Directory
= NULL
;
182 /* Get object structures */
183 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
184 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
185 ObjectType
= ObjectHeader
->Type
;
188 * Check if the handle count is 0, if the object is named,
189 * and if the object isn't a permanent object.
191 if (!(ObjectHeader
->HandleCount
) &&
193 (ObjectNameInfo
->Name
.Length
) &&
194 (ObjectNameInfo
->Directory
) &&
195 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
197 /* Setup a lookup context */
198 ObpInitializeLookupContext(&Context
);
200 /* Lock the directory */
201 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
204 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
205 &ObjectNameInfo
->Name
,
211 /* Lock the object */
212 ObpAcquireObjectLock(ObjectHeader
);
214 /* Make sure we can still delete the object */
215 if (!(ObjectHeader
->HandleCount
) &&
216 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
218 /* First delete it from the directory */
219 ObpDeleteEntryDirectory(&Context
);
221 /* Check if this is a symbolic link */
222 if (ObjectType
== ObSymbolicLinkType
)
224 /* Remove internal name */
225 ObpDeleteSymbolicLinkName(Object
);
228 /* Check if the magic protection flag is set */
229 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
230 if ((ObjectNameInfo
) &&
231 (ObjectNameInfo
->QueryReferences
& 0x40000000))
233 /* Remove protection flag */
234 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
238 /* Get the directory */
239 Directory
= ObjectNameInfo
->Directory
;
242 /* Release the lock */
243 ObpReleaseObjectLock(ObjectHeader
);
246 /* Cleanup after lookup */
247 ObpReleaseLookupContext(&Context
);
249 /* Remove another query reference since we added one on top */
250 ObpDereferenceNameInfo(ObjectNameInfo
);
252 /* Check if we were inserted in a directory */
255 /* We were, so first remove the extra reference we had added */
256 ObpDereferenceNameInfo(ObjectNameInfo
);
258 /* Now dereference the object as well */
259 ObDereferenceObject(Object
);
264 /* Remove the reference we added */
265 ObpDereferenceNameInfo(ObjectNameInfo
);
271 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
272 IN PUNICODE_STRING ObjectName
,
274 IN POBJECT_TYPE ObjectType
,
275 IN KPROCESSOR_MODE AccessMode
,
276 IN OUT PVOID ParseContext
,
277 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
278 IN PVOID InsertObject OPTIONAL
,
279 IN OUT PACCESS_STATE AccessState
,
280 OUT POBP_LOOKUP_CONTEXT LookupContext
,
281 OUT PVOID
*FoundObject
)
284 POBJECT_HEADER ObjectHeader
;
285 UNICODE_STRING ComponentName
, RemainingName
;
286 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
287 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
288 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
290 OB_PARSE_METHOD ParseRoutine
;
292 KPROCESSOR_MODE AccessCheckMode
;
294 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
295 ULONG MaxReparse
= 30;
297 OBTRACE(OB_NAMESPACE_DEBUG
,
298 "%s - Finding Object: %wZ. Expecting: %p\n",
303 /* Initialize starting state */
304 ObpInitializeLookupContext(LookupContext
);
306 Status
= STATUS_SUCCESS
;
309 /* Check if case-insensitivity is checked */
310 if (ObpCaseInsensitive
)
312 /* Check if the object type requests this */
313 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
315 /* Add the flag to disable case sensitivity */
316 Attributes
|= OBJ_CASE_INSENSITIVE
;
320 /* Check if this is a access checks are being forced */
321 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
322 UserMode
: AccessMode
;
324 /* Check if we got a Root Directory */
327 /* We did. Reference it */
328 Status
= ObReferenceObjectByHandle(RootHandle
,
332 (PVOID
*)&RootDirectory
,
334 if (!NT_SUCCESS(Status
)) return Status
;
337 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
339 /* The name cannot start with a separator, unless this is a file */
340 if ((ObjectName
->Buffer
) &&
341 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
342 (ObjectHeader
->Type
!= IoFileObjectType
))
344 /* The syntax is bad, so fail this request */
345 ObDereferenceObject(RootDirectory
);
346 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
349 /* Don't parse a Directory */
350 if (ObjectHeader
->Type
!= ObDirectoryType
)
352 /* Make sure the Object Type has a parse routine */
353 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
356 /* We can't parse a name if we don't have a parse routine */
357 ObDereferenceObject(RootDirectory
);
358 return STATUS_INVALID_HANDLE
;
361 /* Set default parse count */
367 /* Start with the full name */
368 RemainingName
= *ObjectName
;
370 /* Call the Parse Procedure */
371 ObpCalloutStart(&CalloutIrql
);
372 Status
= ParseRoutine(RootDirectory
,
382 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
384 /* Check for success or failure, so not reparse */
385 if ((Status
!= STATUS_REPARSE
) &&
386 (Status
!= STATUS_REPARSE_OBJECT
))
388 /* Check for failure */
389 if (!NT_SUCCESS(Status
))
391 /* Parse routine might not have cleared this, do it */
396 /* Modify status to reflect failure inside Ob */
397 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
400 /* We're done, return the status and object */
401 *FoundObject
= Object
;
402 ObDereferenceObject(RootDirectory
);
405 else if ((!ObjectName
->Length
) ||
406 (!ObjectName
->Buffer
) ||
407 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
409 /* Reparsed to the root directory, so start over */
410 ObDereferenceObject(RootDirectory
);
411 RootDirectory
= ObpRootDirectoryObject
;
413 /* Don't use this anymore, since we're starting at root */
417 else if (--MaxReparse
)
419 /* Try reparsing again */
424 /* Reparsed too many times */
425 ObDereferenceObject(RootDirectory
);
427 /* Return the object and normalized status */
428 *FoundObject
= Object
;
429 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
434 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
436 /* Just return the Root Directory if we didn't get a name*/
437 Status
= ObReferenceObjectByPointer(RootDirectory
,
441 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
443 /* Remove the first reference we added and return the object */
444 ObDereferenceObject(RootDirectory
);
445 *FoundObject
= Object
;
451 /* We did not get a Root Directory, so use the root */
452 RootDirectory
= ObpRootDirectoryObject
;
454 /* It must start with a path separator */
455 if (!(ObjectName
->Length
) ||
456 !(ObjectName
->Buffer
) ||
457 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
459 /* This name is invalid, so fail */
460 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
463 /* Check if the name is only the path separator */
464 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
466 /* So the caller only wants the root directory; do we have one? */
469 /* This must be the first time we're creating it... right? */
472 /* Yes, so return it to ObInsert so that it can create it */
473 Status
= ObReferenceObjectByPointer(InsertObject
,
477 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
482 /* This should never really happen */
484 return STATUS_INVALID_PARAMETER
;
489 /* We do have the root directory, so just return it */
490 Status
= ObReferenceObjectByPointer(RootDirectory
,
494 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
501 /* FIXME: Check if we have a device map */
503 /* Check if this is a possible DOS name */
504 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
507 * This could be one. Does it match the prefix?
508 * Note that as an optimization, the match is done as 64-bit
509 * compare since the prefix is "\??\" which is exactly 8 bytes.
511 * In the second branch, we test for "\??" which is also valid.
512 * This time, we use a 32-bit compare followed by a Unicode
513 * character compare (16-bit), since the sum is 6 bytes.
515 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
516 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
517 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
521 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
523 (*(PULONG
)(ObjectName
->Buffer
) ==
524 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
525 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
526 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
534 /* Check if we were reparsing a symbolic link */
546 RemainingName
= *ObjectName
;
548 /* Disable reparsing again */
551 /* Start parse loop */
557 /* Check if the name starts with a path separator */
558 if ((RemainingName
.Length
) &&
559 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
561 /* Skip the path separator */
562 RemainingName
.Buffer
++;
563 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
566 /* Find the next Part Name */
567 ComponentName
= RemainingName
;
568 while (RemainingName
.Length
)
570 /* Break if we found the \ ending */
571 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
574 RemainingName
.Buffer
++;
575 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
578 /* Get its size and make sure it's valid */
579 ComponentName
.Length
-= RemainingName
.Length
;
580 if (!ComponentName
.Length
)
582 /* Invalid size, fail */
583 Status
= STATUS_OBJECT_NAME_INVALID
;
587 /* Check if we're in the root */
588 if (!Directory
) Directory
= RootDirectory
;
590 /* Check if this is a user-mode call that needs to traverse */
591 if ((AccessCheckMode
!= KernelMode
) &&
592 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
594 /* We shouldn't have referenced a directory yet */
595 ASSERT(ReferencedDirectory
== NULL
);
597 /* Reference the directory */
598 ObReferenceObject(Directory
);
599 ReferencedDirectory
= Directory
;
601 /* Check if we have a parent directory */
604 /* Check for traverse access */
605 if (!ObpCheckTraverseAccess(ParentDirectory
,
612 /* We don't have it, fail */
618 /* Check if we don't have a remaining name yet */
619 if (!RemainingName
.Length
)
621 /* Check if we don't have a referenced directory yet */
622 if (!ReferencedDirectory
)
625 ObReferenceObject(Directory
);
626 ReferencedDirectory
= Directory
;
629 /* Check if we are inserting an object */
632 /* Lock the directory */
633 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
638 Object
= ObpLookupEntryDirectory(Directory
,
641 InsertObject
? FALSE
: TRUE
,
645 /* We didn't find it... do we still have a path? */
646 if (RemainingName
.Length
)
648 /* Then tell the caller the path wasn't found */
649 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
652 else if (!InsertObject
)
654 /* Otherwise, we have a path, but the name isn't valid */
655 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
659 /* Check create access for the object */
660 if (!ObCheckCreateObjectAccess(Directory
,
661 ObjectType
== ObDirectoryType
?
662 DIRECTORY_CREATE_SUBDIRECTORY
:
663 DIRECTORY_CREATE_OBJECT
,
670 /* We don't have create access, fail */
674 /* Get the object header */
675 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
677 /* FIXME: Check if this is a Section Object or Sym Link */
678 /* FIXME: If it is, then check if this isn't session 0 */
679 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
680 /* FIXME: If privilege isn't there, check for unsecure name */
681 /* FIXME: If it isn't a known unsecure name, then fail */
683 /* Create Object Name */
684 NewName
= ExAllocatePoolWithTag(PagedPool
,
685 ComponentName
.Length
,
688 !(ObpInsertEntryDirectory(Directory
,
692 /* Either couldn't allocate the name, or insert failed */
693 if (NewName
) ExFreePool(NewName
);
695 /* Fail due to memory reasons */
696 Status
= STATUS_INSUFFICIENT_RESOURCES
;
700 /* Reference newly to be inserted object */
701 ObReferenceObject(InsertObject
);
703 /* Get the name information */
704 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
706 /* Reference the directory */
707 ObReferenceObject(Directory
);
710 RtlCopyMemory(NewName
,
711 ComponentName
.Buffer
,
712 ComponentName
.Length
);
714 /* Check if we had an old name */
715 if (ObjectNameInfo
->Name
.Buffer
)
718 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
722 ObjectNameInfo
->Name
.Buffer
= NewName
;
723 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
724 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
726 /* Return Status and the Expected Object */
727 Status
= STATUS_SUCCESS
;
728 Object
= InsertObject
;
730 /* Get out of here */
735 /* We found it, so now get its header */
736 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
739 * Check for a parse Procedure, but don't bother to parse for an insert
740 * unless it's a Symbolic Link, in which case we MUST parse
742 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
743 if ((ParseRoutine
) &&
744 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
746 /* Use the Root Directory next time */
749 /* Increment the pointer count */
750 InterlockedExchangeAdd(&ObjectHeader
->PointerCount
, 1);
752 /* Cleanup from the first lookup */
753 ObpReleaseLookupContext(LookupContext
);
755 /* Check if we have a referenced directory */
756 if (ReferencedDirectory
)
758 /* We do, dereference it */
759 ObDereferenceObject(ReferencedDirectory
);
760 ReferencedDirectory
= NULL
;
763 /* Check if we have a referenced parent directory */
764 if (ReferencedParentDirectory
)
766 /* We do, dereference it */
767 ObDereferenceObject(ReferencedParentDirectory
);
768 ReferencedParentDirectory
= NULL
;
771 /* Call the Parse Procedure */
772 ObpCalloutStart(&CalloutIrql
);
773 Status
= ParseRoutine(Object
,
783 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
785 /* Remove our extra reference */
786 ObDereferenceObject(&ObjectHeader
->Body
);
788 /* Check if we have to reparse */
789 if ((Status
== STATUS_REPARSE
) ||
790 (Status
== STATUS_REPARSE_OBJECT
))
795 /* Start over from root if we got sent back there */
796 if ((Status
== STATUS_REPARSE_OBJECT
) ||
797 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
799 /* Check if we got a root directory */
802 /* Stop using it, because we have a new directory now */
803 ObDereferenceObject(RootDirectory
);
808 ParentDirectory
= NULL
;
809 RootDirectory
= ObpRootDirectoryObject
;
811 /* Check for reparse status */
812 if (Status
== STATUS_REPARSE_OBJECT
)
814 /* Don't reparse again */
817 /* Did we actually get an object to which to reparse? */
820 /* We didn't, so set a failure status */
821 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
825 /* We did, so we're free to parse the new object */
831 /* This is a symbolic link */
836 else if (RootDirectory
== ObpRootDirectoryObject
)
838 /* We got STATUS_REPARSE but are at the Root Directory */
840 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
844 else if (!NT_SUCCESS(Status
))
851 /* We didn't reparse but we didn't find the Object Either */
852 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
855 /* Break out of the loop */
860 /* No parse routine...do we still have a remaining name? */
861 if (!RemainingName
.Length
)
863 /* Are we creating an object? */
866 /* Check if this is a user-mode call that needs to traverse */
867 if ((AccessCheckMode
!= KernelMode
) &&
868 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
870 /* Check if we can get it */
871 if (!ObpCheckTraverseAccess(Directory
,
878 /* We don't have access, fail */
884 /* Reference the Object */
885 Status
= ObReferenceObjectByPointer(Object
,
889 if (!NT_SUCCESS(Status
)) Object
= NULL
;
892 /* And get out of the reparse loop */
897 /* We still have a name; check if this is a directory object */
898 if (ObjectHeader
->Type
== ObDirectoryType
)
900 /* Check if we have a referenced parent directory */
901 if (ReferencedParentDirectory
)
904 ObDereferenceObject(ReferencedParentDirectory
);
907 /* Restart the lookup from this directory */
908 ReferencedParentDirectory
= ReferencedDirectory
;
909 ParentDirectory
= Directory
;
911 ReferencedDirectory
= NULL
;
915 /* We still have a name, but no parse routine for it */
916 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
925 /* Check if we failed */
926 if (!NT_SUCCESS(Status
))
928 /* Cleanup after lookup */
929 ObpReleaseLookupContext(LookupContext
);
932 /* Check if we have a device map and dereference it if so */
933 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
935 /* Check if we have a referenced directory and dereference it if so */
936 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
938 /* Check if we have a referenced parent directory */
939 if (ReferencedParentDirectory
)
941 /* We do, dereference it */
942 ObDereferenceObject(ReferencedParentDirectory
);
945 /* Set the found object and check if we got one */
946 *FoundObject
= Object
;
949 /* Nothing was found. Did we reparse or get success? */
950 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
952 /* Set correct failure */
953 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
957 /* Check if we had a root directory */
958 if (RootHandle
) ObDereferenceObject(RootDirectory
);
960 /* Return status to caller */
961 OBTRACE(OB_NAMESPACE_DEBUG
,
962 "%s - Found Object: %p. Expected: %p\n",
969 /* PUBLIC FUNCTIONS *********************************************************/
973 ObQueryNameString(IN PVOID Object
,
974 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
976 OUT PULONG ReturnLength
)
978 POBJECT_HEADER_NAME_INFO LocalInfo
;
979 POBJECT_HEADER ObjectHeader
;
980 POBJECT_DIRECTORY ParentDirectory
;
983 BOOLEAN ObjectIsNamed
;
985 /* Get the Kernel Meta-Structures */
986 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
987 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
989 /* Check if a Query Name Procedure is available */
990 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
992 /* Call the procedure */
993 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
994 return ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1002 /* Check if the object doesn't even have a name */
1003 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1005 /* We're returning the name structure */
1006 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1008 /* Check if we were given enough space */
1009 if (*ReturnLength
> Length
) return STATUS_INFO_LENGTH_MISMATCH
;
1011 /* Return an empty buffer */
1012 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1013 return STATUS_SUCCESS
;
1017 * Find the size needed for the name. We won't do
1018 * this during the Name Creation loop because we want
1019 * to let the caller know that the buffer isn't big
1020 * enough right at the beginning, not work our way through
1021 * and find out at the end
1023 if (Object
== ObpRootDirectoryObject
)
1025 /* Size of the '\' string */
1026 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1030 /* Get the Object Directory and add name of Object */
1031 ParentDirectory
= LocalInfo
->Directory
;
1032 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1034 /* Loop inside the directory to get the top-most one (meaning root) */
1035 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1037 /* Get the Name Information */
1038 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1039 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1041 /* Add the size of the Directory Name */
1042 if (LocalInfo
&& LocalInfo
->Directory
)
1044 /* Size of the '\' string + Directory Name */
1045 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1046 LocalInfo
->Name
.Length
;
1048 /* Move to next parent Directory */
1049 ParentDirectory
= LocalInfo
->Directory
;
1053 /* Directory with no name. We append "...\" */
1054 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1060 /* Finally, add the name of the structure and the null char */
1061 *ReturnLength
= NameSize
+
1062 sizeof(OBJECT_NAME_INFORMATION
) +
1063 sizeof(UNICODE_NULL
);
1065 /* Check if we were given enough space */
1066 if (*ReturnLength
> Length
) return STATUS_INFO_LENGTH_MISMATCH
;
1069 * Now we will actually create the name. We work backwards because
1070 * it's easier to start off from the Name we have and walk up the
1071 * parent directories. We use the same logic as Name Length calculation.
1073 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1074 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1075 *--ObjectName
= UNICODE_NULL
;
1077 /* Check if the object is actually the Root directory */
1078 if (Object
== ObpRootDirectoryObject
)
1080 /* This is already the Root Directory, return "\\" */
1081 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1082 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1083 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1084 sizeof(UNICODE_NULL
));
1085 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1086 return STATUS_SUCCESS
;
1090 /* Start by adding the Object's Name */
1091 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1092 LocalInfo
->Name
.Length
);
1093 RtlCopyMemory(ObjectName
,
1094 LocalInfo
->Name
.Buffer
,
1095 LocalInfo
->Name
.Length
);
1097 /* Now parse the Parent directories until we reach the top */
1098 ParentDirectory
= LocalInfo
->Directory
;
1099 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1101 /* Get the name information */
1102 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1103 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1106 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1108 /* Add the Parent Directory's Name */
1109 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1112 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1113 LocalInfo
->Name
.Length
);
1114 RtlCopyMemory(ObjectName
,
1115 LocalInfo
->Name
.Buffer
,
1116 LocalInfo
->Name
.Length
);
1118 /* Move to next parent */
1119 ParentDirectory
= LocalInfo
->Directory
;
1123 /* Directory without a name, we add "..." */
1124 ObjectName
-= sizeof(L
"...");
1125 ObjectName
= L
"...";
1130 /* Add Root Directory Name */
1131 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1132 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1133 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1134 sizeof(UNICODE_NULL
));
1135 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1138 /* Return success */
1139 return STATUS_SUCCESS
;
1144 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
1145 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
1150 * FIXME: This is an ugly hack for now, to always return the System Device Map
1151 * instead of returning the Process Device Map. Not important yet since we don't use it
1154 /* FIXME: Acquire the DeviceMap Spinlock */
1155 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
1158 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
1159 RtlCopyMemory(DeviceMapInfo
->Query
.DriveType
,
1160 ObSystemDeviceMap
->DriveType
,
1161 sizeof(ObSystemDeviceMap
->DriveType
));
1163 /* FIXME: Release the DeviceMap Spinlock */
1164 // KeReleasepinLock(DeviceMap->Lock, OldIrql);