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
)
116 PDEVICE_MAP DeviceMap
;
118 /* Get the pointer to this process devicemap and reset it
119 holding devicemap lock */
120 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
121 DeviceMap
= Process
->DeviceMap
;
122 Process
->DeviceMap
= NULL
;
123 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
125 /* Continue only if there is a devicemap to dereference */
128 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
130 /* Delete the device map link and dereference it */
131 if (--DeviceMap
->ReferenceCount
)
133 /* Nobody is referencing it anymore, unlink the DOS directory */
134 DeviceMap
->DosDevicesDirectory
->DeviceMap
= NULL
;
136 /* Release the devicemap lock */
137 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
139 /* Dereference the DOS Devices Directory and free the Device Map */
140 ObDereferenceObject(DeviceMap
->DosDevicesDirectory
);
141 ExFreePool(DeviceMap
);
145 /* Release the devicemap lock */
146 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
153 ObInheritDeviceMap(IN PEPROCESS Parent
,
154 IN PEPROCESS Process
)
156 /* FIXME: Devicemap Support */
160 * @name ObpDeleteNameCheck
162 * The ObpDeleteNameCheck routine checks if a named object should be
163 * removed from the object directory namespace.
166 * Pointer to the object to check for possible removal.
170 * @remarks An object is removed if the following 4 criteria are met:
171 * 1) The object has 0 handles open
172 * 2) The object is in the directory namespace and has a name
173 * 3) The object is not permanent
178 ObpDeleteNameCheck(IN PVOID Object
)
180 POBJECT_HEADER ObjectHeader
;
181 OBP_LOOKUP_CONTEXT Context
;
182 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
183 POBJECT_TYPE ObjectType
;
184 PVOID Directory
= NULL
;
186 /* Get object structures */
187 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
188 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
189 ObjectType
= ObjectHeader
->Type
;
192 * Check if the handle count is 0, if the object is named,
193 * and if the object isn't a permanent object.
195 if (!(ObjectHeader
->HandleCount
) &&
197 (ObjectNameInfo
->Name
.Length
) &&
198 (ObjectNameInfo
->Directory
) &&
199 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
201 /* Setup a lookup context */
202 ObpInitializeLookupContext(&Context
);
204 /* Lock the directory */
205 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
208 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
209 &ObjectNameInfo
->Name
,
215 /* Lock the object */
216 ObpAcquireObjectLock(ObjectHeader
);
218 /* Make sure we can still delete the object */
219 if (!(ObjectHeader
->HandleCount
) &&
220 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
222 /* First delete it from the directory */
223 ObpDeleteEntryDirectory(&Context
);
225 /* Check if this is a symbolic link */
226 if (ObjectType
== ObSymbolicLinkType
)
228 /* Remove internal name */
229 ObpDeleteSymbolicLinkName(Object
);
232 /* Check if the magic protection flag is set */
233 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
234 if ((ObjectNameInfo
) &&
235 (ObjectNameInfo
->QueryReferences
& 0x40000000))
237 /* Remove protection flag */
238 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
242 /* Get the directory */
243 Directory
= ObjectNameInfo
->Directory
;
246 /* Release the lock */
247 ObpReleaseObjectLock(ObjectHeader
);
250 /* Cleanup after lookup */
251 ObpReleaseLookupContext(&Context
);
253 /* Remove another query reference since we added one on top */
254 ObpDereferenceNameInfo(ObjectNameInfo
);
256 /* Check if we were inserted in a directory */
259 /* We were, so first remove the extra reference we had added */
260 ObpDereferenceNameInfo(ObjectNameInfo
);
262 /* Now dereference the object as well */
263 ObDereferenceObject(Object
);
268 /* Remove the reference we added */
269 ObpDereferenceNameInfo(ObjectNameInfo
);
275 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
276 IN PUNICODE_STRING ObjectName
,
278 IN POBJECT_TYPE ObjectType
,
279 IN KPROCESSOR_MODE AccessMode
,
280 IN OUT PVOID ParseContext
,
281 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
282 IN PVOID InsertObject OPTIONAL
,
283 IN OUT PACCESS_STATE AccessState
,
284 OUT POBP_LOOKUP_CONTEXT LookupContext
,
285 OUT PVOID
*FoundObject
)
288 POBJECT_HEADER ObjectHeader
;
289 UNICODE_STRING ComponentName
, RemainingName
;
290 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
291 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
292 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
294 OB_PARSE_METHOD ParseRoutine
;
296 KPROCESSOR_MODE AccessCheckMode
;
298 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
299 ULONG MaxReparse
= 30;
301 OBTRACE(OB_NAMESPACE_DEBUG
,
302 "%s - Finding Object: %wZ. Expecting: %p\n",
307 /* Initialize starting state */
308 ObpInitializeLookupContext(LookupContext
);
310 Status
= STATUS_SUCCESS
;
313 /* Check if case-insensitivity is checked */
314 if (ObpCaseInsensitive
)
316 /* Check if the object type requests this */
317 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
319 /* Add the flag to disable case sensitivity */
320 Attributes
|= OBJ_CASE_INSENSITIVE
;
324 /* Check if this is a access checks are being forced */
325 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
326 UserMode
: AccessMode
;
328 /* Check if we got a Root Directory */
331 /* We did. Reference it */
332 Status
= ObReferenceObjectByHandle(RootHandle
,
336 (PVOID
*)&RootDirectory
,
338 if (!NT_SUCCESS(Status
)) return Status
;
341 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
343 /* The name cannot start with a separator, unless this is a file */
344 if ((ObjectName
->Buffer
) &&
345 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
346 (ObjectHeader
->Type
!= IoFileObjectType
))
348 /* The syntax is bad, so fail this request */
349 ObDereferenceObject(RootDirectory
);
350 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
353 /* Don't parse a Directory */
354 if (ObjectHeader
->Type
!= ObDirectoryType
)
356 /* Make sure the Object Type has a parse routine */
357 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
360 /* We can't parse a name if we don't have a parse routine */
361 ObDereferenceObject(RootDirectory
);
362 return STATUS_INVALID_HANDLE
;
365 /* Set default parse count */
371 /* Start with the full name */
372 RemainingName
= *ObjectName
;
374 /* Call the Parse Procedure */
375 ObpCalloutStart(&CalloutIrql
);
376 Status
= ParseRoutine(RootDirectory
,
386 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
388 /* Check for success or failure, so not reparse */
389 if ((Status
!= STATUS_REPARSE
) &&
390 (Status
!= STATUS_REPARSE_OBJECT
))
392 /* Check for failure */
393 if (!NT_SUCCESS(Status
))
395 /* Parse routine might not have cleared this, do it */
400 /* Modify status to reflect failure inside Ob */
401 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
404 /* We're done, return the status and object */
405 *FoundObject
= Object
;
406 ObDereferenceObject(RootDirectory
);
409 else if ((!ObjectName
->Length
) ||
410 (!ObjectName
->Buffer
) ||
411 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
413 /* Reparsed to the root directory, so start over */
414 ObDereferenceObject(RootDirectory
);
415 RootDirectory
= ObpRootDirectoryObject
;
417 /* Don't use this anymore, since we're starting at root */
421 else if (--MaxReparse
)
423 /* Try reparsing again */
428 /* Reparsed too many times */
429 ObDereferenceObject(RootDirectory
);
431 /* Return the object and normalized status */
432 *FoundObject
= Object
;
433 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
438 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
440 /* Just return the Root Directory if we didn't get a name */
441 Status
= ObReferenceObjectByPointer(RootDirectory
,
445 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
447 /* Remove the first reference we added and return the object */
448 ObDereferenceObject(RootDirectory
);
449 *FoundObject
= Object
;
455 /* We did not get a Root Directory, so use the root */
456 RootDirectory
= ObpRootDirectoryObject
;
458 /* It must start with a path separator */
459 if (!(ObjectName
->Length
) ||
460 !(ObjectName
->Buffer
) ||
461 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
463 /* This name is invalid, so fail */
464 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
467 /* Check if the name is only the path separator */
468 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
470 /* So the caller only wants the root directory; do we have one? */
473 /* This must be the first time we're creating it... right? */
476 /* Yes, so return it to ObInsert so that it can create it */
477 Status
= ObReferenceObjectByPointer(InsertObject
,
481 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
486 /* This should never really happen */
488 return STATUS_INVALID_PARAMETER
;
493 /* We do have the root directory, so just return it */
494 Status
= ObReferenceObjectByPointer(RootDirectory
,
498 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
505 /* FIXME: Check if we have a device map */
507 /* Check if this is a possible DOS name */
508 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
511 * This could be one. Does it match the prefix?
512 * Note that as an optimization, the match is done as 64-bit
513 * compare since the prefix is "\??\" which is exactly 8 bytes.
515 * In the second branch, we test for "\??" which is also valid.
516 * This time, we use a 32-bit compare followed by a Unicode
517 * character compare (16-bit), since the sum is 6 bytes.
519 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
520 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
521 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
525 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
527 (*(PULONG
)(ObjectName
->Buffer
) ==
528 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
529 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
530 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
538 /* Check if we were reparsing a symbolic link */
547 while (Reparse
&& MaxReparse
)
550 RemainingName
= *ObjectName
;
552 /* Disable reparsing again */
555 /* Start parse loop */
561 /* Check if the name starts with a path separator */
562 if ((RemainingName
.Length
) &&
563 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
565 /* Skip the path separator */
566 RemainingName
.Buffer
++;
567 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
570 /* Find the next Part Name */
571 ComponentName
= RemainingName
;
572 while (RemainingName
.Length
)
574 /* Break if we found the \ ending */
575 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
578 RemainingName
.Buffer
++;
579 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
582 /* Get its size and make sure it's valid */
583 ComponentName
.Length
-= RemainingName
.Length
;
584 if (!ComponentName
.Length
)
586 /* Invalid size, fail */
587 Status
= STATUS_OBJECT_NAME_INVALID
;
591 /* Check if we're in the root */
592 if (!Directory
) Directory
= RootDirectory
;
594 /* Check if this is a user-mode call that needs to traverse */
595 if ((AccessCheckMode
!= KernelMode
) &&
596 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
598 /* We shouldn't have referenced a directory yet */
599 ASSERT(ReferencedDirectory
== NULL
);
601 /* Reference the directory */
602 ObReferenceObject(Directory
);
603 ReferencedDirectory
= Directory
;
605 /* Check if we have a parent directory */
608 /* Check for traverse access */
609 if (!ObpCheckTraverseAccess(ParentDirectory
,
616 /* We don't have it, fail */
622 /* Check if we don't have a remaining name yet */
623 if (!RemainingName
.Length
)
625 /* Check if we don't have a referenced directory yet */
626 if (!ReferencedDirectory
)
629 ObReferenceObject(Directory
);
630 ReferencedDirectory
= Directory
;
633 /* Check if we are inserting an object */
636 /* Lock the directory */
637 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
642 Object
= ObpLookupEntryDirectory(Directory
,
645 InsertObject
? FALSE
: TRUE
,
649 /* We didn't find it... do we still have a path? */
650 if (RemainingName
.Length
)
652 /* Then tell the caller the path wasn't found */
653 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
656 else if (!InsertObject
)
658 /* Otherwise, we have a path, but the name isn't valid */
659 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
663 /* Check create access for the object */
664 if (!ObCheckCreateObjectAccess(Directory
,
665 ObjectType
== ObDirectoryType
?
666 DIRECTORY_CREATE_SUBDIRECTORY
:
667 DIRECTORY_CREATE_OBJECT
,
674 /* We don't have create access, fail */
678 /* Get the object header */
679 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
681 /* FIXME: Check if this is a Section Object or Sym Link */
682 /* FIXME: If it is, then check if this isn't session 0 */
683 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
684 /* FIXME: If privilege isn't there, check for unsecure name */
685 /* FIXME: If it isn't a known unsecure name, then fail */
687 /* Create Object Name */
688 NewName
= ExAllocatePoolWithTag(PagedPool
,
689 ComponentName
.Length
,
692 !(ObpInsertEntryDirectory(Directory
,
696 /* Either couldn't allocate the name, or insert failed */
697 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
699 /* Fail due to memory reasons */
700 Status
= STATUS_INSUFFICIENT_RESOURCES
;
704 /* Reference newly to be inserted object */
705 ObReferenceObject(InsertObject
);
707 /* Get the name information */
708 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
710 /* Reference the directory */
711 ObReferenceObject(Directory
);
714 RtlCopyMemory(NewName
,
715 ComponentName
.Buffer
,
716 ComponentName
.Length
);
718 /* Check if we had an old name */
719 if (ObjectNameInfo
->Name
.Buffer
)
722 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
726 ObjectNameInfo
->Name
.Buffer
= NewName
;
727 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
728 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
730 /* Return Status and the Expected Object */
731 Status
= STATUS_SUCCESS
;
732 Object
= InsertObject
;
734 /* Get out of here */
739 /* We found it, so now get its header */
740 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
743 * Check for a parse Procedure, but don't bother to parse for an insert
744 * unless it's a Symbolic Link, in which case we MUST parse
746 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
747 if ((ParseRoutine
) &&
748 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
750 /* Use the Root Directory next time */
753 /* Increment the pointer count */
754 InterlockedExchangeAdd(&ObjectHeader
->PointerCount
, 1);
756 /* Cleanup from the first lookup */
757 ObpReleaseLookupContext(LookupContext
);
759 /* Check if we have a referenced directory */
760 if (ReferencedDirectory
)
762 /* We do, dereference it */
763 ObDereferenceObject(ReferencedDirectory
);
764 ReferencedDirectory
= NULL
;
767 /* Check if we have a referenced parent directory */
768 if (ReferencedParentDirectory
)
770 /* We do, dereference it */
771 ObDereferenceObject(ReferencedParentDirectory
);
772 ReferencedParentDirectory
= NULL
;
775 /* Call the Parse Procedure */
776 ObpCalloutStart(&CalloutIrql
);
777 Status
= ParseRoutine(Object
,
787 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
789 /* Remove our extra reference */
790 ObDereferenceObject(&ObjectHeader
->Body
);
792 /* Check if we have to reparse */
793 if ((Status
== STATUS_REPARSE
) ||
794 (Status
== STATUS_REPARSE_OBJECT
))
805 /* Start over from root if we got sent back there */
806 if ((Status
== STATUS_REPARSE_OBJECT
) ||
807 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
809 /* Check if we got a root directory */
812 /* Stop using it, because we have a new directory now */
813 ObDereferenceObject(RootDirectory
);
818 ParentDirectory
= NULL
;
819 RootDirectory
= ObpRootDirectoryObject
;
821 /* Check for reparse status */
822 if (Status
== STATUS_REPARSE_OBJECT
)
824 /* Don't reparse again */
827 /* Did we actually get an object to which to reparse? */
830 /* We didn't, so set a failure status */
831 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
835 /* We did, so we're free to parse the new object */
841 /* This is a symbolic link */
846 else if (RootDirectory
== ObpRootDirectoryObject
)
848 /* We got STATUS_REPARSE but are at the Root Directory */
850 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
854 else if (!NT_SUCCESS(Status
))
861 /* We didn't reparse but we didn't find the Object Either */
862 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
865 /* Break out of the loop */
870 /* No parse routine...do we still have a remaining name? */
871 if (!RemainingName
.Length
)
873 /* Are we creating an object? */
876 /* Check if this is a user-mode call that needs to traverse */
877 if ((AccessCheckMode
!= KernelMode
) &&
878 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
880 /* Check if we can get it */
881 if (!ObpCheckTraverseAccess(Directory
,
888 /* We don't have access, fail */
894 /* Reference the Object */
895 Status
= ObReferenceObjectByPointer(Object
,
899 if (!NT_SUCCESS(Status
)) Object
= NULL
;
902 /* And get out of the reparse loop */
907 /* We still have a name; check if this is a directory object */
908 if (ObjectHeader
->Type
== ObDirectoryType
)
910 /* Check if we have a referenced parent directory */
911 if (ReferencedParentDirectory
)
914 ObDereferenceObject(ReferencedParentDirectory
);
917 /* Restart the lookup from this directory */
918 ReferencedParentDirectory
= ReferencedDirectory
;
919 ParentDirectory
= Directory
;
921 ReferencedDirectory
= NULL
;
925 /* We still have a name, but no parse routine for it */
926 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
935 /* Check if we failed */
936 if (!NT_SUCCESS(Status
))
938 /* Cleanup after lookup */
939 ObpReleaseLookupContext(LookupContext
);
942 /* Check if we have a device map and dereference it if so */
943 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
945 /* Check if we have a referenced directory and dereference it if so */
946 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
948 /* Check if we have a referenced parent directory */
949 if (ReferencedParentDirectory
)
951 /* We do, dereference it */
952 ObDereferenceObject(ReferencedParentDirectory
);
955 /* Set the found object and check if we got one */
956 *FoundObject
= Object
;
959 /* Nothing was found. Did we reparse or get success? */
960 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
962 /* Set correct failure */
963 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
967 /* Check if we had a root directory */
968 if (RootHandle
) ObDereferenceObject(RootDirectory
);
970 /* Return status to caller */
971 OBTRACE(OB_NAMESPACE_DEBUG
,
972 "%s - Found Object: %p. Expected: %p\n",
979 /* PUBLIC FUNCTIONS *********************************************************/
983 ObQueryNameString(IN PVOID Object
,
984 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
986 OUT PULONG ReturnLength
)
988 POBJECT_HEADER_NAME_INFO LocalInfo
;
989 POBJECT_HEADER ObjectHeader
;
990 POBJECT_DIRECTORY ParentDirectory
;
993 BOOLEAN ObjectIsNamed
;
994 NTSTATUS Status
= STATUS_SUCCESS
;
996 /* Get the Kernel Meta-Structures */
997 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
998 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1000 /* Check if a Query Name Procedure is available */
1001 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1003 /* Call the procedure inside SEH */
1004 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1008 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1015 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1017 /* Return the exception code */
1018 Status
= _SEH2_GetExceptionCode();
1025 /* Check if the object doesn't even have a name */
1026 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1028 Status
= STATUS_SUCCESS
;
1032 /* We're returning the name structure */
1033 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1035 /* Check if we were given enough space */
1036 if (*ReturnLength
> Length
)
1038 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1042 /* Return an empty buffer */
1043 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1046 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1048 /* Return the exception code */
1049 Status
= _SEH2_GetExceptionCode();
1057 * Find the size needed for the name. We won't do
1058 * this during the Name Creation loop because we want
1059 * to let the caller know that the buffer isn't big
1060 * enough right at the beginning, not work our way through
1061 * and find out at the end
1065 if (Object
== ObpRootDirectoryObject
)
1067 /* Size of the '\' string */
1068 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1072 /* Get the Object Directory and add name of Object */
1073 ParentDirectory
= LocalInfo
->Directory
;
1074 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1076 /* Loop inside the directory to get the top-most one (meaning root) */
1077 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1079 /* Get the Name Information */
1080 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1081 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1083 /* Add the size of the Directory Name */
1084 if (LocalInfo
&& LocalInfo
->Directory
)
1086 /* Size of the '\' string + Directory Name */
1087 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1088 LocalInfo
->Name
.Length
;
1090 /* Move to next parent Directory */
1091 ParentDirectory
= LocalInfo
->Directory
;
1095 /* Directory with no name. We append "...\" */
1096 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1102 /* Finally, add the name of the structure and the null char */
1103 *ReturnLength
= NameSize
+
1104 sizeof(OBJECT_NAME_INFORMATION
) +
1105 sizeof(UNICODE_NULL
);
1107 /* Check if we were given enough space */
1108 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1111 * Now we will actually create the name. We work backwards because
1112 * it's easier to start off from the Name we have and walk up the
1113 * parent directories. We use the same logic as Name Length calculation.
1115 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1116 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1117 *--ObjectName
= UNICODE_NULL
;
1119 /* Check if the object is actually the Root directory */
1120 if (Object
== ObpRootDirectoryObject
)
1122 /* This is already the Root Directory, return "\\" */
1123 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1124 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1125 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1126 sizeof(UNICODE_NULL
));
1127 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1128 Status
= STATUS_SUCCESS
;
1132 /* Start by adding the Object's Name */
1133 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1134 LocalInfo
->Name
.Length
);
1135 RtlCopyMemory(ObjectName
,
1136 LocalInfo
->Name
.Buffer
,
1137 LocalInfo
->Name
.Length
);
1139 /* Now parse the Parent directories until we reach the top */
1140 ParentDirectory
= LocalInfo
->Directory
;
1141 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1143 /* Get the name information */
1144 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1145 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1148 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1150 /* Add the Parent Directory's Name */
1151 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1154 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1155 LocalInfo
->Name
.Length
);
1156 RtlCopyMemory(ObjectName
,
1157 LocalInfo
->Name
.Buffer
,
1158 LocalInfo
->Name
.Length
);
1160 /* Move to next parent */
1161 ParentDirectory
= LocalInfo
->Directory
;
1165 /* Directory without a name, we add "..." */
1166 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1168 sizeof(UNICODE_NULL
));
1169 RtlCopyMemory(ObjectName
,
1171 sizeof(L
"...") + sizeof(UNICODE_NULL
));
1176 /* Add Root Directory Name */
1177 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1178 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1179 ObjectNameInfo
->Name
.MaximumLength
=
1180 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1181 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1184 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1186 /* Return the exception code */
1187 Status
= _SEH2_GetExceptionCode();
1191 /* Return success */
1197 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
1198 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
1201 * FIXME: This is an ugly hack for now, to always return the System Device Map
1202 * instead of returning the Process Device Map. Not important yet since we don't use it
1205 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
1208 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
1209 RtlCopyMemory(DeviceMapInfo
->Query
.DriveType
,
1210 ObSystemDeviceMap
->DriveType
,
1211 sizeof(ObSystemDeviceMap
->DriveType
));
1213 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
1218 ObIsDosDeviceLocallyMapped(
1220 OUT PUCHAR DosDeviceState
)
1222 /* check parameters */
1223 if (Index
< 1 || Index
> 26)
1226 return STATUS_INVALID_PARAMETER
;
1230 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
1232 /* get drive mapping status */
1233 *DosDeviceState
= (ObSystemDeviceMap
->DriveMap
& (1 << Index
)) != 0;
1236 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
1239 return STATUS_SUCCESS
;