3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/namespc.c
6 * PURPOSE: Manages the system namespace
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES ***************************************************************/
15 #include <internal/debug.h>
17 extern ULONG NtGlobalFlag
;
19 /* GLOBALS ****************************************************************/
21 POBJECT_TYPE ObDirectoryType
= NULL
;
22 POBJECT_TYPE ObTypeObjectType
= NULL
;
24 PDIRECTORY_OBJECT NameSpaceRoot
= NULL
;
25 PDIRECTORY_OBJECT ObpTypeDirectoryObject
= NULL
;
26 /* FIXME: Move this somewhere else once devicemap support is in */
27 PDEVICE_MAP ObSystemDeviceMap
= NULL
;
28 KEVENT ObpDefaultObject
;
30 static GENERIC_MAPPING ObpDirectoryMapping
= {
31 STANDARD_RIGHTS_READ
|DIRECTORY_QUERY
|DIRECTORY_TRAVERSE
,
32 STANDARD_RIGHTS_WRITE
|DIRECTORY_CREATE_OBJECT
|DIRECTORY_CREATE_SUBDIRECTORY
,
33 STANDARD_RIGHTS_EXECUTE
|DIRECTORY_QUERY
|DIRECTORY_TRAVERSE
,
34 DIRECTORY_ALL_ACCESS
};
36 static GENERIC_MAPPING ObpTypeMapping
= {
38 STANDARD_RIGHTS_WRITE
,
39 STANDARD_RIGHTS_EXECUTE
,
44 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
45 PUNICODE_STRING ObjectName
,
46 POBJECT_TYPE ObjectType
,
48 POBJECT_HEADER
*ObjectHeader
);
50 /* FUNCTIONS **************************************************************/
56 ObReferenceObjectByName(PUNICODE_STRING ObjectPath
,
58 PACCESS_STATE PassedAccessState
,
59 ACCESS_MASK DesiredAccess
,
60 POBJECT_TYPE ObjectType
,
61 KPROCESSOR_MODE AccessMode
,
66 UNICODE_STRING RemainingPath
;
67 UNICODE_STRING ObjectName
;
68 OBJECT_ATTRIBUTES ObjectAttributes
;
69 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
74 /* capture the ObjectPath */
75 Status
= RtlCaptureUnicodeString(&ObjectName
,
77 NonPagedPool
, /* FIXME */
80 if (!NT_SUCCESS(Status
))
82 DPRINT("RtlCaptureUnicodeString() failed (Status %lx)\n", Status
);
86 InitializeObjectAttributes(&ObjectAttributes
,
88 Attributes
| OBJ_OPENIF
,
92 /* "Capture" all the info, it doesn't make sense to capture from the kernel
93 stack as the information should be safe anyway...just do a raw copy of the
94 data into the OBJECT_CREATE_INFORMATION structure */
95 DPRINT("Capturing Create Info\n");
96 Status
= ObpCaptureObjectAttributes(&ObjectAttributes
,
97 KernelMode
, /* raw copy! */
102 if (!NT_SUCCESS(Status
))
104 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
108 Status
= ObFindObject(&ObjectCreateInfo
,
114 /* we don't need to release the "captured" object attributes! Nothing was allocated! */
116 ObpReleaseCapturedAttributes(&ObjectCreateInfo
,
122 /* free the captured ObjectPath if needed */
123 RtlReleaseCapturedUnicodeString(&ObjectName
,
127 if (!NT_SUCCESS(Status
))
131 DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath
.Buffer
, Object
);
133 if (RemainingPath
.Buffer
!= NULL
|| Object
== NULL
)
135 DPRINT("Object %p\n", Object
);
137 RtlFreeUnicodeString (&RemainingPath
);
138 return(STATUS_OBJECT_NAME_NOT_FOUND
);
141 RtlFreeUnicodeString (&RemainingPath
);
142 return(STATUS_SUCCESS
);
146 /**********************************************************************
151 * Obtain a handle to an existing object.
175 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes
,
176 IN POBJECT_TYPE ObjectType
,
177 IN OUT PVOID ParseContext
,
178 IN KPROCESSOR_MODE AccessMode
,
179 IN ACCESS_MASK DesiredAccess
,
180 IN PACCESS_STATE PassedAccessState
,
183 UNICODE_STRING RemainingPath
;
185 UNICODE_STRING ObjectName
;
186 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
191 DPRINT("ObOpenObjectByName(...)\n");
193 /* Capture all the info */
194 DPRINT("Capturing Create Info\n");
195 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
201 if (!NT_SUCCESS(Status
))
203 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
207 Status
= ObFindObject(&ObjectCreateInfo
,
212 ObpReleaseCapturedAttributes(&ObjectCreateInfo
,
216 if (!NT_SUCCESS(Status
))
218 DPRINT("ObFindObject() failed (Status %lx)\n", Status
);
222 DPRINT("OBject: %x, Remaining Path: %wZ\n", Object
, &RemainingPath
);
225 RtlFreeUnicodeString(&RemainingPath
);
226 return STATUS_UNSUCCESSFUL
;
228 if (RemainingPath
.Buffer
!= NULL
)
230 if (wcschr(RemainingPath
.Buffer
+ 1, L
'\\') == NULL
)
231 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
233 Status
=STATUS_OBJECT_PATH_NOT_FOUND
;
234 RtlFreeUnicodeString(&RemainingPath
);
235 ObDereferenceObject(Object
);
239 Status
= ObpCreateHandle(PsGetCurrentProcess(),
245 ObDereferenceObject(Object
);
246 RtlFreeUnicodeString(&RemainingPath
);
253 ObQueryDeviceMapInformation(PEPROCESS Process
,
254 PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
259 * FIXME: This is an ugly hack for now, to always return the System Device Map
260 * instead of returning the Process Device Map. Not important yet since we don't use it
263 /* FIXME: Acquire the DeviceMap Spinlock */
264 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
267 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
268 RtlMoveMemory(DeviceMapInfo
->Query
.DriveType
, ObSystemDeviceMap
->DriveType
, sizeof(ObSystemDeviceMap
->DriveType
));
270 /* FIXME: Release the DeviceMap Spinlock */
271 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
275 ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent
,
276 POBJECT_HEADER Header
,
279 * FUNCTION: Add an entry to a namespace directory
281 * Parent = directory to add in
282 * Header = Header of the object to add the entry for
283 * Name = Name to give the entry
288 ASSERT(HEADER_TO_OBJECT_NAME(Header
));
289 HEADER_TO_OBJECT_NAME(Header
)->Directory
= Parent
;
291 KeAcquireSpinLock(&Parent
->Lock
, &oldlvl
);
292 InsertTailList(&Parent
->head
, &Header
->Entry
);
293 KeReleaseSpinLock(&Parent
->Lock
, oldlvl
);
298 ObpRemoveEntryDirectory(POBJECT_HEADER Header
)
300 * FUNCTION: Remove an entry from a namespace directory
302 * Header = Header of the object to remove
307 DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header
);
309 KeAcquireSpinLock(&(HEADER_TO_OBJECT_NAME(Header
)->Directory
->Lock
),&oldlvl
);
310 if (Header
->Entry
.Flink
&& Header
->Entry
.Blink
)
312 RemoveEntryList(&(Header
->Entry
));
313 Header
->Entry
.Flink
= Header
->Entry
.Blink
= NULL
;
315 KeReleaseSpinLock(&(HEADER_TO_OBJECT_NAME(Header
)->Directory
->Lock
),oldlvl
);
320 ObpCreateDirectory(OB_OPEN_REASON Reason
,
324 ACCESS_MASK GrantedAccess
)
326 PDIRECTORY_OBJECT Directory
= ObjectBody
;
328 if (Reason
== ObCreateHandle
)
330 InitializeListHead(&Directory
->head
);
331 KeInitializeSpinLock(&Directory
->Lock
);
334 return STATUS_SUCCESS
;
338 ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject
,
342 PLIST_ENTRY current
= DirectoryObject
->head
.Flink
;
343 POBJECT_HEADER current_obj
;
345 DPRINT("ObFindEntryDirectory(dir %x, name %S)\n",DirectoryObject
, Name
);
349 return(DirectoryObject
);
351 if (Name
[0]=='.' && Name
[1]==0)
353 return(DirectoryObject
);
355 if (Name
[0]=='.' && Name
[1]=='.' && Name
[2]==0)
357 return(HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(DirectoryObject
))->Directory
);
359 while (current
!=(&(DirectoryObject
->head
)))
361 current_obj
= CONTAINING_RECORD(current
,OBJECT_HEADER
,Entry
);
362 DPRINT(" Scanning: %S for: %S\n",HEADER_TO_OBJECT_NAME(current_obj
)->Name
.Buffer
, Name
);
363 if (Attributes
& OBJ_CASE_INSENSITIVE
)
365 if (_wcsicmp(HEADER_TO_OBJECT_NAME(current_obj
)->Name
.Buffer
, Name
)==0)
367 DPRINT("Found it %x\n",¤t_obj
->Body
);
368 return(¤t_obj
->Body
);
373 if ( wcscmp(HEADER_TO_OBJECT_NAME(current_obj
)->Name
.Buffer
, Name
)==0)
375 DPRINT("Found it %x\n",¤t_obj
->Body
);
376 return(¤t_obj
->Body
);
379 current
= current
->Flink
;
381 DPRINT(" Not Found: %s() = NULL\n",__FUNCTION__
);
387 ObpParseDirectory(PVOID Object
,
389 PUNICODE_STRING FullPath
,
398 DPRINT("ObpParseDirectory(Object %x, Path %x, *Path %S)\n",
405 return STATUS_UNSUCCESSFUL
;
412 End
= wcschr(Start
, L
'\\');
418 KeAcquireSpinLock(&(((PDIRECTORY_OBJECT
)Object
)->Lock
), &oldlvl
);
419 FoundObject
= ObpFindEntryDirectory(Object
, Start
, Attributes
);
420 if (FoundObject
== NULL
)
422 KeReleaseSpinLock(&(((PDIRECTORY_OBJECT
)Object
)->Lock
), oldlvl
);
427 return STATUS_UNSUCCESSFUL
;
430 ObReferenceObjectByPointer(FoundObject
,
431 STANDARD_RIGHTS_REQUIRED
,
434 KeReleaseSpinLock(&(((PDIRECTORY_OBJECT
)Object
)->Lock
), oldlvl
);
445 *NextObject
= FoundObject
;
447 return STATUS_SUCCESS
;
454 OBJECT_ATTRIBUTES ObjectAttributes
;
456 SECURITY_DESCRIPTOR SecurityDescriptor
;
457 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
459 /* Initialize the security descriptor cache */
462 /* Initialize the Default Event */
463 KeInitializeEvent(&ObpDefaultObject
, NotificationEvent
, TRUE
);
465 /* Create the Type Type */
466 DPRINT("Creating Type Type\n");
467 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
468 RtlInitUnicodeString(&Name
, L
"Type");
469 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
470 ObjectTypeInitializer
.ValidAccessMask
= OBJECT_TYPE_ALL_ACCESS
;
471 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
472 ObjectTypeInitializer
.MaintainTypeList
= TRUE
;
473 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
474 ObjectTypeInitializer
.GenericMapping
= ObpTypeMapping
;
475 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(OBJECT_TYPE
);
476 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObTypeObjectType
);
478 /* Create the Directory Type */
479 DPRINT("Creating Directory Type\n");
480 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
481 RtlInitUnicodeString(&Name
, L
"Directory");
482 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
483 ObjectTypeInitializer
.ValidAccessMask
= DIRECTORY_ALL_ACCESS
;
484 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
485 ObjectTypeInitializer
.OpenProcedure
= ObpCreateDirectory
;
486 ObjectTypeInitializer
.ParseProcedure
= ObpParseDirectory
;
487 ObjectTypeInitializer
.MaintainTypeList
= FALSE
;
488 ObjectTypeInitializer
.GenericMapping
= ObpDirectoryMapping
;
489 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DIRECTORY_OBJECT
);
490 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObDirectoryType
);
492 /* Create security descriptor */
493 RtlCreateSecurityDescriptor(&SecurityDescriptor
,
494 SECURITY_DESCRIPTOR_REVISION1
);
495 RtlSetOwnerSecurityDescriptor(&SecurityDescriptor
,
498 RtlSetGroupSecurityDescriptor(&SecurityDescriptor
,
501 RtlSetDaclSecurityDescriptor(&SecurityDescriptor
,
506 /* Create root directory */
507 DPRINT("Creating Root Directory\n");
508 InitializeObjectAttributes(&ObjectAttributes
,
512 &SecurityDescriptor
);
513 ObCreateObject(KernelMode
,
518 sizeof(DIRECTORY_OBJECT
),
521 (PVOID
*)&NameSpaceRoot
);
522 ObInsertObject((PVOID
)NameSpaceRoot
,
524 DIRECTORY_ALL_ACCESS
,
529 /* Create '\ObjectTypes' directory */
530 RtlInitUnicodeString(&Name
, L
"\\ObjectTypes");
531 InitializeObjectAttributes(&ObjectAttributes
,
535 &SecurityDescriptor
);
536 ObCreateObject(KernelMode
,
541 sizeof(DIRECTORY_OBJECT
),
544 (PVOID
*)&ObpTypeDirectoryObject
);
545 ObInsertObject((PVOID
)ObpTypeDirectoryObject
,
547 DIRECTORY_ALL_ACCESS
,
552 /* Insert the two objects we already created but couldn't add */
553 /* NOTE: Uses TypeList & Creator Info in OB 2.0 */
554 ObpAddEntryDirectory(ObpTypeDirectoryObject
, BODY_TO_HEADER(ObTypeObjectType
), NULL
);
555 ObpAddEntryDirectory(ObpTypeDirectoryObject
, BODY_TO_HEADER(ObDirectoryType
), NULL
);
557 /* Create 'symbolic link' object type */
558 ObInitSymbolicLinkImplementation();
560 /* FIXME: Hack Hack! */
561 ObSystemDeviceMap
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*ObSystemDeviceMap
), TAG('O', 'b', 'D', 'm'));
562 RtlZeroMemory(ObSystemDeviceMap
, sizeof(*ObSystemDeviceMap
));
567 ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer
,
568 PUNICODE_STRING TypeName
,
569 POBJECT_TYPE
*ObjectType
)
571 POBJECT_HEADER Header
;
572 POBJECT_TYPE LocalObjectType
;
576 DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", TypeName
);
578 /* Allocate the Object */
579 Status
= ObpAllocateObject(NULL
,
582 OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE
)),
584 if (!NT_SUCCESS(Status
))
586 DPRINT1("ObpAllocateObject failed!\n");
590 LocalObjectType
= (POBJECT_TYPE
)&Header
->Body
;
591 DPRINT("Local ObjectType: %p Header: %p \n", LocalObjectType
, Header
);
593 /* Check if this is the first Object Type */
594 if (!ObTypeObjectType
)
596 ObTypeObjectType
= LocalObjectType
;
597 Header
->Type
= ObTypeObjectType
;
598 LocalObjectType
->Key
= TAG('O', 'b', 'j', 'T');
603 Tag
[0] = TypeName
->Buffer
[0];
604 Tag
[1] = TypeName
->Buffer
[1];
605 Tag
[2] = TypeName
->Buffer
[2];
606 Tag
[3] = TypeName
->Buffer
[3];
609 DPRINT("Convert: %s \n", Tag
);
610 LocalObjectType
->Key
= *(PULONG
)Tag
;
614 LocalObjectType
->TypeInfo
= *ObjectTypeInitializer
;
615 LocalObjectType
->Name
= *TypeName
;
616 LocalObjectType
->TypeInfo
.PoolType
= ObjectTypeInitializer
->PoolType
;
618 /* These two flags need to be manually set up */
619 Header
->Flags
|= OB_FLAG_KERNEL_MODE
| OB_FLAG_PERMANENT
;
621 /* Check if we have to maintain a type list */
622 if (NtGlobalFlag
& FLG_MAINTAIN_OBJECT_TYPELIST
)
625 LocalObjectType
->TypeInfo
.MaintainTypeList
= TRUE
;
628 /* Calculate how much space our header'll take up */
629 HeaderSize
= sizeof(OBJECT_HEADER
) + sizeof(OBJECT_HEADER_NAME_INFO
) +
630 (ObjectTypeInitializer
->MaintainHandleCount
?
631 sizeof(OBJECT_HEADER_HANDLE_INFO
) : 0);
633 /* Update the Pool Charges */
634 if (ObjectTypeInitializer
->PoolType
== NonPagedPool
)
636 LocalObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
+= HeaderSize
;
640 LocalObjectType
->TypeInfo
.DefaultPagedPoolCharge
+= HeaderSize
;
643 /* All objects types need a security procedure */
644 if (!ObjectTypeInitializer
->SecurityProcedure
)
646 LocalObjectType
->TypeInfo
.SecurityProcedure
= SeDefaultObjectMethod
;
649 /* Select the Wait Object */
650 if (LocalObjectType
->TypeInfo
.UseDefaultObject
)
652 /* Add the SYNCHRONIZE access mask since it's waitable */
653 LocalObjectType
->TypeInfo
.ValidAccessMask
|= SYNCHRONIZE
;
655 /* Use the "Default Object", a simple event */
656 LocalObjectType
->DefaultObject
= &ObpDefaultObject
;
658 /* Special system objects get an optimized hack so they can be waited on */
659 else if (TypeName
->Length
== 8 && !wcscmp(TypeName
->Buffer
, L
"File"))
661 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(FILE_OBJECT
, Event
);
663 /* FIXME: When LPC stops sucking, add a hack for Waitable Ports */
666 /* No default Object */
667 LocalObjectType
->DefaultObject
= NULL
;
670 /* Initialize Object Type components */
671 ExInitializeResourceLite(&LocalObjectType
->Mutex
);
672 InitializeListHead(&LocalObjectType
->TypeList
);
674 /* Insert it into the Object Directory */
675 if (ObpTypeDirectoryObject
)
677 ObpAddEntryDirectory(ObpTypeDirectoryObject
, Header
, TypeName
->Buffer
);
678 ObReferenceObject(ObpTypeDirectoryObject
);
681 *ObjectType
= LocalObjectType
;