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 RootName
, TargetName
, LinkName
;
41 HANDLE Handle
, SymHandle
;
44 /* Create the global DosDevices directory \?? */
45 RtlInitUnicodeString(&RootName
, L
"\\GLOBAL??");
46 InitializeObjectAttributes(&ObjectAttributes
,
51 Status
= NtCreateDirectoryObject(&Handle
,
54 if (!NT_SUCCESS(Status
)) return Status
;
56 /*********************************************\
57 |*** HACK until we support device mappings ***|
58 |*** Add a symlink \??\ <--> \GLOBAL??\ ***|
59 \*********************************************/
60 RtlInitUnicodeString(&LinkName
, L
"\\??");
61 InitializeObjectAttributes(&ObjectAttributes
,
66 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
67 SYMBOLIC_LINK_ALL_ACCESS
,
70 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
71 /*********************************************\
72 \*********************************************/
74 // FIXME: Create a device mapping for the global \?? directory
77 * Initialize the \??\GLOBALROOT symbolic link
78 * pointing to the root directory \ .
80 RtlInitUnicodeString(&LinkName
, L
"GLOBALROOT");
81 RtlInitUnicodeString(&TargetName
, L
"");
82 InitializeObjectAttributes(&ObjectAttributes
,
87 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
88 SYMBOLIC_LINK_ALL_ACCESS
,
91 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
94 * Initialize the \??\Global symbolic link pointing to the global
95 * DosDevices directory \?? . It is used to access the global \??
96 * by user-mode components which, by default, use a per-session
97 * DosDevices directory.
99 RtlInitUnicodeString(&LinkName
, L
"Global");
100 InitializeObjectAttributes(&ObjectAttributes
,
105 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
106 SYMBOLIC_LINK_ALL_ACCESS
,
109 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
111 /* Close the directory handle */
113 if (!NT_SUCCESS(Status
)) return Status
;
116 * Initialize the \DosDevices symbolic link pointing to the global
117 * DosDevices directory \?? , for backward compatibility with
118 * Windows NT-2000 systems.
120 RtlCreateUnicodeString(&LinkName
, L
"\\DosDevices");
121 RtlInitUnicodeString(&RootName
, (PCWSTR
)&ObpDosDevicesShortNameRoot
);
122 InitializeObjectAttributes(&ObjectAttributes
,
127 Status
= NtCreateSymbolicLinkObject(&SymHandle
,
128 SYMBOLIC_LINK_ALL_ACCESS
,
131 if (NT_SUCCESS(Status
)) NtClose(SymHandle
);
133 /* FIXME: Hack Hack! */
134 ObSystemDeviceMap
= ExAllocatePoolWithTag(NonPagedPool
,
135 sizeof(*ObSystemDeviceMap
),
137 if (!ObSystemDeviceMap
) return STATUS_INSUFFICIENT_RESOURCES
;
138 RtlZeroMemory(ObSystemDeviceMap
, sizeof(*ObSystemDeviceMap
));
146 ObDereferenceDeviceMap(IN PEPROCESS Process
)
148 PDEVICE_MAP DeviceMap
;
150 /* Get the pointer to this process devicemap and reset it
151 holding devicemap lock */
152 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
153 DeviceMap
= Process
->DeviceMap
;
154 Process
->DeviceMap
= NULL
;
155 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
157 /* Continue only if there is a devicemap to dereference */
160 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
162 /* Delete the device map link and dereference it */
163 if (--DeviceMap
->ReferenceCount
)
165 /* Nobody is referencing it anymore, unlink the DOS directory */
166 DeviceMap
->DosDevicesDirectory
->DeviceMap
= NULL
;
168 /* Release the devicemap lock */
169 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
171 /* Dereference the DOS Devices Directory and free the Device Map */
172 ObDereferenceObject(DeviceMap
->DosDevicesDirectory
);
173 ExFreePool(DeviceMap
);
177 /* Release the devicemap lock */
178 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
185 ObInheritDeviceMap(IN PEPROCESS Parent
,
186 IN PEPROCESS Process
)
188 /* FIXME: Devicemap Support */
192 * @name ObpDeleteNameCheck
194 * The ObpDeleteNameCheck routine checks if a named object should be
195 * removed from the object directory namespace.
198 * Pointer to the object to check for possible removal.
202 * @remarks An object is removed if the following 4 criteria are met:
203 * 1) The object has 0 handles open
204 * 2) The object is in the directory namespace and has a name
205 * 3) The object is not permanent
210 ObpDeleteNameCheck(IN PVOID Object
)
212 POBJECT_HEADER ObjectHeader
;
213 OBP_LOOKUP_CONTEXT Context
;
214 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
215 POBJECT_TYPE ObjectType
;
216 PVOID Directory
= NULL
;
218 /* Get object structures */
219 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
220 ObjectNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
221 ObjectType
= ObjectHeader
->Type
;
224 * Check if the handle count is 0, if the object is named,
225 * and if the object isn't a permanent object.
227 if (!(ObjectHeader
->HandleCount
) &&
229 (ObjectNameInfo
->Name
.Length
) &&
230 (ObjectNameInfo
->Directory
) &&
231 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
233 /* Setup a lookup context */
234 ObpInitializeLookupContext(&Context
);
236 /* Lock the directory */
237 ObpAcquireDirectoryLockExclusive(ObjectNameInfo
->Directory
, &Context
);
240 Object
= ObpLookupEntryDirectory(ObjectNameInfo
->Directory
,
241 &ObjectNameInfo
->Name
,
247 /* Lock the object */
248 ObpAcquireObjectLock(ObjectHeader
);
250 /* Make sure we can still delete the object */
251 if (!(ObjectHeader
->HandleCount
) &&
252 !(ObjectHeader
->Flags
& OB_FLAG_PERMANENT
))
254 /* First delete it from the directory */
255 ObpDeleteEntryDirectory(&Context
);
257 /* Check if this is a symbolic link */
258 if (ObjectType
== ObSymbolicLinkType
)
260 /* Remove internal name */
261 ObpDeleteSymbolicLinkName(Object
);
264 /* Check if the magic protection flag is set */
265 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
266 if ((ObjectNameInfo
) &&
267 (ObjectNameInfo
->QueryReferences
& 0x40000000))
269 /* Remove protection flag */
270 InterlockedExchangeAdd((PLONG
)&ObjectNameInfo
->QueryReferences
,
274 /* Get the directory */
275 Directory
= ObjectNameInfo
->Directory
;
278 /* Release the lock */
279 ObpReleaseObjectLock(ObjectHeader
);
282 /* Cleanup after lookup */
283 ObpReleaseLookupContext(&Context
);
285 /* Remove another query reference since we added one on top */
286 ObpDereferenceNameInfo(ObjectNameInfo
);
288 /* Check if we were inserted in a directory */
291 /* We were, so first remove the extra reference we had added */
292 ObpDereferenceNameInfo(ObjectNameInfo
);
294 /* Now dereference the object as well */
295 ObDereferenceObject(Object
);
300 /* Remove the reference we added */
301 ObpDereferenceNameInfo(ObjectNameInfo
);
307 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL
,
308 IN PUNICODE_STRING ObjectName
,
310 IN POBJECT_TYPE ObjectType
,
311 IN KPROCESSOR_MODE AccessMode
,
312 IN OUT PVOID ParseContext
,
313 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
314 IN PVOID InsertObject OPTIONAL
,
315 IN OUT PACCESS_STATE AccessState
,
316 OUT POBP_LOOKUP_CONTEXT LookupContext
,
317 OUT PVOID
*FoundObject
)
320 POBJECT_HEADER ObjectHeader
;
321 UNICODE_STRING ComponentName
, RemainingName
;
322 BOOLEAN Reparse
= FALSE
, SymLink
= FALSE
;
323 POBJECT_DIRECTORY Directory
= NULL
, ParentDirectory
= NULL
, RootDirectory
;
324 POBJECT_DIRECTORY ReferencedDirectory
= NULL
, ReferencedParentDirectory
= NULL
;
326 OB_PARSE_METHOD ParseRoutine
;
328 KPROCESSOR_MODE AccessCheckMode
;
330 POBJECT_HEADER_NAME_INFO ObjectNameInfo
;
331 ULONG MaxReparse
= 30;
333 OBTRACE(OB_NAMESPACE_DEBUG
,
334 "%s - Finding Object: %wZ. Expecting: %p\n",
339 /* Initialize starting state */
340 ObpInitializeLookupContext(LookupContext
);
342 Status
= STATUS_SUCCESS
;
345 /* Check if case-insensitivity is checked */
346 if (ObpCaseInsensitive
)
348 /* Check if the object type requests this */
349 if (!(ObjectType
) || (ObjectType
->TypeInfo
.CaseInsensitive
))
351 /* Add the flag to disable case sensitivity */
352 Attributes
|= OBJ_CASE_INSENSITIVE
;
356 /* Check if this is a access checks are being forced */
357 AccessCheckMode
= (Attributes
& OBJ_FORCE_ACCESS_CHECK
) ?
358 UserMode
: AccessMode
;
360 /* Check if we got a Root Directory */
363 /* We did. Reference it */
364 Status
= ObReferenceObjectByHandle(RootHandle
,
368 (PVOID
*)&RootDirectory
,
370 if (!NT_SUCCESS(Status
)) return Status
;
373 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(RootDirectory
);
375 /* The name cannot start with a separator, unless this is a file */
376 if ((ObjectName
->Buffer
) &&
377 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) &&
378 (ObjectHeader
->Type
!= IoFileObjectType
))
380 /* The syntax is bad, so fail this request */
381 ObDereferenceObject(RootDirectory
);
382 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
385 /* Don't parse a Directory */
386 if (ObjectHeader
->Type
!= ObDirectoryType
)
388 /* Make sure the Object Type has a parse routine */
389 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
392 /* We can't parse a name if we don't have a parse routine */
393 ObDereferenceObject(RootDirectory
);
394 return STATUS_INVALID_HANDLE
;
397 /* Set default parse count */
403 /* Start with the full name */
404 RemainingName
= *ObjectName
;
406 /* Call the Parse Procedure */
407 ObpCalloutStart(&CalloutIrql
);
408 Status
= ParseRoutine(RootDirectory
,
418 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
420 /* Check for success or failure, so not reparse */
421 if ((Status
!= STATUS_REPARSE
) &&
422 (Status
!= STATUS_REPARSE_OBJECT
))
424 /* Check for failure */
425 if (!NT_SUCCESS(Status
))
427 /* Parse routine might not have cleared this, do it */
432 /* Modify status to reflect failure inside Ob */
433 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
436 /* We're done, return the status and object */
437 *FoundObject
= Object
;
438 ObDereferenceObject(RootDirectory
);
441 else if ((!ObjectName
->Length
) ||
442 (!ObjectName
->Buffer
) ||
443 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
445 /* Reparsed to the root directory, so start over */
446 ObDereferenceObject(RootDirectory
);
447 RootDirectory
= ObpRootDirectoryObject
;
449 /* Don't use this anymore, since we're starting at root */
453 else if (--MaxReparse
)
455 /* Try reparsing again */
460 /* Reparsed too many times */
461 ObDereferenceObject(RootDirectory
);
463 /* Return the object and normalized status */
464 *FoundObject
= Object
;
465 if (!Object
) Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
470 else if (!(ObjectName
->Length
) || !(ObjectName
->Buffer
))
472 /* Just return the Root Directory if we didn't get a name */
473 Status
= ObReferenceObjectByPointer(RootDirectory
,
477 if (NT_SUCCESS(Status
)) Object
= RootDirectory
;
479 /* Remove the first reference we added and return the object */
480 ObDereferenceObject(RootDirectory
);
481 *FoundObject
= Object
;
487 /* We did not get a Root Directory, so use the root */
488 RootDirectory
= ObpRootDirectoryObject
;
490 /* It must start with a path separator */
491 if (!(ObjectName
->Length
) ||
492 !(ObjectName
->Buffer
) ||
493 (ObjectName
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
))
495 /* This name is invalid, so fail */
496 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
499 /* Check if the name is only the path separator */
500 if (ObjectName
->Length
== sizeof(OBJ_NAME_PATH_SEPARATOR
))
502 /* So the caller only wants the root directory; do we have one? */
505 /* This must be the first time we're creating it... right? */
508 /* Yes, so return it to ObInsert so that it can create it */
509 Status
= ObReferenceObjectByPointer(InsertObject
,
513 if (NT_SUCCESS(Status
)) *FoundObject
= InsertObject
;
518 /* This should never really happen */
520 return STATUS_INVALID_PARAMETER
;
525 /* We do have the root directory, so just return it */
526 Status
= ObReferenceObjectByPointer(RootDirectory
,
530 if (NT_SUCCESS(Status
)) *FoundObject
= RootDirectory
;
537 /* FIXME: Check if we have a device map */
539 /* Check if this is a possible DOS name */
540 if (!((ULONG_PTR
)(ObjectName
->Buffer
) & 7))
543 * This could be one. Does it match the prefix?
544 * Note that as an optimization, the match is done as 64-bit
545 * compare since the prefix is "\??\" which is exactly 8 bytes.
547 * In the second branch, we test for "\??" which is also valid.
548 * This time, we use a 32-bit compare followed by a Unicode
549 * character compare (16-bit), since the sum is 6 bytes.
551 if ((ObjectName
->Length
>= ObpDosDevicesShortName
.Length
) &&
552 (*(PULONGLONG
)(ObjectName
->Buffer
) ==
553 ObpDosDevicesShortNamePrefix
.Alignment
.QuadPart
))
557 else if ((ObjectName
->Length
== ObpDosDevicesShortName
.Length
-
559 (*(PULONG
)(ObjectName
->Buffer
) ==
560 ObpDosDevicesShortNameRoot
.Alignment
.LowPart
) &&
561 (*((PWCHAR
)(ObjectName
->Buffer
) + 2) ==
562 (WCHAR
)(ObpDosDevicesShortNameRoot
.Alignment
.HighPart
)))
570 /* Check if we were reparsing a symbolic link */
579 while (Reparse
&& MaxReparse
)
582 RemainingName
= *ObjectName
;
584 /* Disable reparsing again */
587 /* Start parse loop */
593 /* Check if the name starts with a path separator */
594 if ((RemainingName
.Length
) &&
595 (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
597 /* Skip the path separator */
598 RemainingName
.Buffer
++;
599 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
602 /* Find the next Part Name */
603 ComponentName
= RemainingName
;
604 while (RemainingName
.Length
)
606 /* Break if we found the \ ending */
607 if (RemainingName
.Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
) break;
610 RemainingName
.Buffer
++;
611 RemainingName
.Length
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
614 /* Get its size and make sure it's valid */
615 ComponentName
.Length
-= RemainingName
.Length
;
616 if (!ComponentName
.Length
)
618 /* Invalid size, fail */
619 Status
= STATUS_OBJECT_NAME_INVALID
;
623 /* Check if we're in the root */
624 if (!Directory
) Directory
= RootDirectory
;
626 /* Check if this is a user-mode call that needs to traverse */
627 if ((AccessCheckMode
!= KernelMode
) &&
628 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
630 /* We shouldn't have referenced a directory yet */
631 ASSERT(ReferencedDirectory
== NULL
);
633 /* Reference the directory */
634 ObReferenceObject(Directory
);
635 ReferencedDirectory
= Directory
;
637 /* Check if we have a parent directory */
640 /* Check for traverse access */
641 if (!ObpCheckTraverseAccess(ParentDirectory
,
648 /* We don't have it, fail */
654 /* Check if we don't have a remaining name yet */
655 if (!RemainingName
.Length
)
657 /* Check if we don't have a referenced directory yet */
658 if (!ReferencedDirectory
)
661 ObReferenceObject(Directory
);
662 ReferencedDirectory
= Directory
;
665 /* Check if we are inserting an object */
668 /* Lock the directory */
669 ObpAcquireDirectoryLockExclusive(Directory
, LookupContext
);
674 Object
= ObpLookupEntryDirectory(Directory
,
677 InsertObject
? FALSE
: TRUE
,
681 /* We didn't find it... do we still have a path? */
682 if (RemainingName
.Length
)
684 /* Then tell the caller the path wasn't found */
685 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
688 else if (!InsertObject
)
690 /* Otherwise, we have a path, but the name isn't valid */
691 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
695 /* Check create access for the object */
696 if (!ObCheckCreateObjectAccess(Directory
,
697 ObjectType
== ObDirectoryType
?
698 DIRECTORY_CREATE_SUBDIRECTORY
:
699 DIRECTORY_CREATE_OBJECT
,
706 /* We don't have create access, fail */
710 /* Get the object header */
711 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(InsertObject
);
713 /* FIXME: Check if this is a Section Object or Sym Link */
714 /* FIXME: If it is, then check if this isn't session 0 */
715 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
716 /* FIXME: If privilege isn't there, check for unsecure name */
717 /* FIXME: If it isn't a known unsecure name, then fail */
719 /* Create Object Name */
720 NewName
= ExAllocatePoolWithTag(PagedPool
,
721 ComponentName
.Length
,
724 !(ObpInsertEntryDirectory(Directory
,
728 /* Either couldn't allocate the name, or insert failed */
729 if (NewName
) ExFreePoolWithTag(NewName
, OB_NAME_TAG
);
731 /* Fail due to memory reasons */
732 Status
= STATUS_INSUFFICIENT_RESOURCES
;
736 /* Reference newly to be inserted object */
737 ObReferenceObject(InsertObject
);
739 /* Get the name information */
740 ObjectNameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
742 /* Reference the directory */
743 ObReferenceObject(Directory
);
746 RtlCopyMemory(NewName
,
747 ComponentName
.Buffer
,
748 ComponentName
.Length
);
750 /* Check if we had an old name */
751 if (ObjectNameInfo
->Name
.Buffer
)
754 ExFreePoolWithTag(ObjectNameInfo
->Name
.Buffer
, OB_NAME_TAG
);
758 ObjectNameInfo
->Name
.Buffer
= NewName
;
759 ObjectNameInfo
->Name
.Length
= ComponentName
.Length
;
760 ObjectNameInfo
->Name
.MaximumLength
= ComponentName
.Length
;
762 /* Return Status and the Expected Object */
763 Status
= STATUS_SUCCESS
;
764 Object
= InsertObject
;
766 /* Get out of here */
771 /* We found it, so now get its header */
772 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
775 * Check for a parse Procedure, but don't bother to parse for an insert
776 * unless it's a Symbolic Link, in which case we MUST parse
778 ParseRoutine
= ObjectHeader
->Type
->TypeInfo
.ParseProcedure
;
779 if ((ParseRoutine
) &&
780 (!(InsertObject
) || (ParseRoutine
== ObpParseSymbolicLink
)))
782 /* Use the Root Directory next time */
785 /* Increment the pointer count */
786 InterlockedExchangeAdd(&ObjectHeader
->PointerCount
, 1);
788 /* Cleanup from the first lookup */
789 ObpReleaseLookupContext(LookupContext
);
791 /* Check if we have a referenced directory */
792 if (ReferencedDirectory
)
794 /* We do, dereference it */
795 ObDereferenceObject(ReferencedDirectory
);
796 ReferencedDirectory
= NULL
;
799 /* Check if we have a referenced parent directory */
800 if (ReferencedParentDirectory
)
802 /* We do, dereference it */
803 ObDereferenceObject(ReferencedParentDirectory
);
804 ReferencedParentDirectory
= NULL
;
807 /* Call the Parse Procedure */
808 ObpCalloutStart(&CalloutIrql
);
809 Status
= ParseRoutine(Object
,
819 ObpCalloutEnd(CalloutIrql
, "Parse", ObjectHeader
->Type
, Object
);
821 /* Remove our extra reference */
822 ObDereferenceObject(&ObjectHeader
->Body
);
824 /* Check if we have to reparse */
825 if ((Status
== STATUS_REPARSE
) ||
826 (Status
== STATUS_REPARSE_OBJECT
))
837 /* Start over from root if we got sent back there */
838 if ((Status
== STATUS_REPARSE_OBJECT
) ||
839 (ObjectName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
))
841 /* Check if we got a root directory */
844 /* Stop using it, because we have a new directory now */
845 ObDereferenceObject(RootDirectory
);
850 ParentDirectory
= NULL
;
851 RootDirectory
= ObpRootDirectoryObject
;
853 /* Check for reparse status */
854 if (Status
== STATUS_REPARSE_OBJECT
)
856 /* Don't reparse again */
859 /* Did we actually get an object to which to reparse? */
862 /* We didn't, so set a failure status */
863 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
867 /* We did, so we're free to parse the new object */
873 /* This is a symbolic link */
878 else if (RootDirectory
== ObpRootDirectoryObject
)
880 /* We got STATUS_REPARSE but are at the Root Directory */
882 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
886 else if (!NT_SUCCESS(Status
))
893 /* We didn't reparse but we didn't find the Object Either */
894 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
897 /* Break out of the loop */
902 /* No parse routine...do we still have a remaining name? */
903 if (!RemainingName
.Length
)
905 /* Are we creating an object? */
908 /* Check if this is a user-mode call that needs to traverse */
909 if ((AccessCheckMode
!= KernelMode
) &&
910 !(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
))
912 /* Check if we can get it */
913 if (!ObpCheckTraverseAccess(Directory
,
920 /* We don't have access, fail */
926 /* Reference the Object */
927 Status
= ObReferenceObjectByPointer(Object
,
931 if (!NT_SUCCESS(Status
)) Object
= NULL
;
934 /* And get out of the reparse loop */
939 /* We still have a name; check if this is a directory object */
940 if (ObjectHeader
->Type
== ObDirectoryType
)
942 /* Check if we have a referenced parent directory */
943 if (ReferencedParentDirectory
)
946 ObDereferenceObject(ReferencedParentDirectory
);
949 /* Restart the lookup from this directory */
950 ReferencedParentDirectory
= ReferencedDirectory
;
951 ParentDirectory
= Directory
;
953 ReferencedDirectory
= NULL
;
957 /* We still have a name, but no parse routine for it */
958 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
967 /* Check if we failed */
968 if (!NT_SUCCESS(Status
))
970 /* Cleanup after lookup */
971 ObpReleaseLookupContext(LookupContext
);
974 /* Check if we have a device map and dereference it if so */
975 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
977 /* Check if we have a referenced directory and dereference it if so */
978 if (ReferencedDirectory
) ObDereferenceObject(ReferencedDirectory
);
980 /* Check if we have a referenced parent directory */
981 if (ReferencedParentDirectory
)
983 /* We do, dereference it */
984 ObDereferenceObject(ReferencedParentDirectory
);
987 /* Set the found object and check if we got one */
988 *FoundObject
= Object
;
991 /* Nothing was found. Did we reparse or get success? */
992 if ((Status
== STATUS_REPARSE
) || (NT_SUCCESS(Status
)))
994 /* Set correct failure */
995 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
999 /* Check if we had a root directory */
1000 if (RootHandle
) ObDereferenceObject(RootDirectory
);
1002 /* Return status to caller */
1003 OBTRACE(OB_NAMESPACE_DEBUG
,
1004 "%s - Found Object: %p. Expected: %p\n",
1011 /* PUBLIC FUNCTIONS *********************************************************/
1015 ObQueryNameString(IN PVOID Object
,
1016 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1018 OUT PULONG ReturnLength
)
1020 POBJECT_HEADER_NAME_INFO LocalInfo
;
1021 POBJECT_HEADER ObjectHeader
;
1022 POBJECT_DIRECTORY ParentDirectory
;
1025 BOOLEAN ObjectIsNamed
;
1026 NTSTATUS Status
= STATUS_SUCCESS
;
1028 /* Get the Kernel Meta-Structures */
1029 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(Object
);
1030 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1032 /* Check if a Query Name Procedure is available */
1033 if (ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure
)
1035 /* Call the procedure inside SEH */
1036 ObjectIsNamed
= ((LocalInfo
) && (LocalInfo
->Name
.Length
> 0));
1040 Status
= ObjectHeader
->Type
->TypeInfo
.QueryNameProcedure(Object
,
1047 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1049 /* Return the exception code */
1050 Status
= _SEH2_GetExceptionCode();
1057 /* Check if the object doesn't even have a name */
1058 if (!(LocalInfo
) || !(LocalInfo
->Name
.Buffer
))
1060 Status
= STATUS_SUCCESS
;
1064 /* We're returning the name structure */
1065 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1067 /* Check if we were given enough space */
1068 if (*ReturnLength
> Length
)
1070 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1074 /* Return an empty buffer */
1075 RtlInitEmptyUnicodeString(&ObjectNameInfo
->Name
, NULL
, 0);
1078 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1080 /* Return the exception code */
1081 Status
= _SEH2_GetExceptionCode();
1089 * Find the size needed for the name. We won't do
1090 * this during the Name Creation loop because we want
1091 * to let the caller know that the buffer isn't big
1092 * enough right at the beginning, not work our way through
1093 * and find out at the end
1097 if (Object
== ObpRootDirectoryObject
)
1099 /* Size of the '\' string */
1100 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
);
1104 /* Get the Object Directory and add name of Object */
1105 ParentDirectory
= LocalInfo
->Directory
;
1106 NameSize
= sizeof(OBJ_NAME_PATH_SEPARATOR
) + LocalInfo
->Name
.Length
;
1108 /* Loop inside the directory to get the top-most one (meaning root) */
1109 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1111 /* Get the Name Information */
1112 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1113 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1115 /* Add the size of the Directory Name */
1116 if (LocalInfo
&& LocalInfo
->Directory
)
1118 /* Size of the '\' string + Directory Name */
1119 NameSize
+= sizeof(OBJ_NAME_PATH_SEPARATOR
) +
1120 LocalInfo
->Name
.Length
;
1122 /* Move to next parent Directory */
1123 ParentDirectory
= LocalInfo
->Directory
;
1127 /* Directory with no name. We append "...\" */
1128 NameSize
+= sizeof(L
"...") + sizeof(OBJ_NAME_PATH_SEPARATOR
);
1134 /* Finally, add the name of the structure and the null char */
1135 *ReturnLength
= NameSize
+
1136 sizeof(OBJECT_NAME_INFORMATION
) +
1137 sizeof(UNICODE_NULL
);
1139 /* Check if we were given enough space */
1140 if (*ReturnLength
> Length
) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH
);
1143 * Now we will actually create the name. We work backwards because
1144 * it's easier to start off from the Name we have and walk up the
1145 * parent directories. We use the same logic as Name Length calculation.
1147 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1148 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectNameInfo
+ *ReturnLength
);
1149 *--ObjectName
= UNICODE_NULL
;
1151 /* Check if the object is actually the Root directory */
1152 if (Object
== ObpRootDirectoryObject
)
1154 /* This is already the Root Directory, return "\\" */
1155 *--ObjectName
= OBJ_NAME_PATH_SEPARATOR
;
1156 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1157 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)(NameSize
+
1158 sizeof(UNICODE_NULL
));
1159 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1160 Status
= STATUS_SUCCESS
;
1164 /* Start by adding the Object's Name */
1165 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1166 LocalInfo
->Name
.Length
);
1167 RtlCopyMemory(ObjectName
,
1168 LocalInfo
->Name
.Buffer
,
1169 LocalInfo
->Name
.Length
);
1171 /* Now parse the Parent directories until we reach the top */
1172 ParentDirectory
= LocalInfo
->Directory
;
1173 while ((ParentDirectory
!= ObpRootDirectoryObject
) && (ParentDirectory
))
1175 /* Get the name information */
1176 LocalInfo
= OBJECT_HEADER_TO_NAME_INFO(
1177 OBJECT_TO_OBJECT_HEADER(ParentDirectory
));
1180 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1182 /* Add the Parent Directory's Name */
1183 if (LocalInfo
&& LocalInfo
->Name
.Buffer
)
1186 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1187 LocalInfo
->Name
.Length
);
1188 RtlCopyMemory(ObjectName
,
1189 LocalInfo
->Name
.Buffer
,
1190 LocalInfo
->Name
.Length
);
1192 /* Move to next parent */
1193 ParentDirectory
= LocalInfo
->Directory
;
1197 /* Directory without a name, we add "..." */
1198 ObjectName
= (PWCH
)((ULONG_PTR
)ObjectName
-
1200 sizeof(UNICODE_NULL
));
1201 RtlCopyMemory(ObjectName
, L
"...", sizeof(L
"..."));
1206 /* Add Root Directory Name */
1207 *(--ObjectName
) = OBJ_NAME_PATH_SEPARATOR
;
1208 ObjectNameInfo
->Name
.Length
= (USHORT
)NameSize
;
1209 ObjectNameInfo
->Name
.MaximumLength
=
1210 (USHORT
)(NameSize
+ sizeof(UNICODE_NULL
));
1211 ObjectNameInfo
->Name
.Buffer
= ObjectName
;
1214 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1216 /* Return the exception code */
1217 Status
= _SEH2_GetExceptionCode();
1221 /* Return success */
1227 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
1228 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
1231 * FIXME: This is an ugly hack for now, to always return the System Device Map
1232 * instead of returning the Process Device Map. Not important yet since we don't use it
1235 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
1238 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
1239 RtlCopyMemory(DeviceMapInfo
->Query
.DriveType
,
1240 ObSystemDeviceMap
->DriveType
,
1241 sizeof(ObSystemDeviceMap
->DriveType
));
1243 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
1248 ObIsDosDeviceLocallyMapped(
1250 OUT PUCHAR DosDeviceState
)
1252 /* check parameters */
1253 if (Index
< 1 || Index
> 26)
1256 return STATUS_INVALID_PARAMETER
;
1260 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
1262 /* get drive mapping status */
1263 *DosDeviceState
= (ObSystemDeviceMap
->DriveMap
& (1 << Index
)) != 0;
1266 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
1269 return STATUS_SUCCESS
;