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 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, ObInit)
22 extern ULONG NtGlobalFlag
;
24 /* GLOBALS ****************************************************************/
26 POBJECT_TYPE ObDirectoryType
= NULL
;
27 POBJECT_TYPE ObTypeObjectType
= NULL
;
29 PDIRECTORY_OBJECT NameSpaceRoot
= NULL
;
30 PDIRECTORY_OBJECT ObpTypeDirectoryObject
= NULL
;
31 /* FIXME: Move this somewhere else once devicemap support is in */
32 PDEVICE_MAP ObSystemDeviceMap
= NULL
;
33 KEVENT ObpDefaultObject
;
35 static GENERIC_MAPPING ObpDirectoryMapping
= {
36 STANDARD_RIGHTS_READ
|DIRECTORY_QUERY
|DIRECTORY_TRAVERSE
,
37 STANDARD_RIGHTS_WRITE
|DIRECTORY_CREATE_OBJECT
|DIRECTORY_CREATE_SUBDIRECTORY
,
38 STANDARD_RIGHTS_EXECUTE
|DIRECTORY_QUERY
|DIRECTORY_TRAVERSE
,
39 DIRECTORY_ALL_ACCESS
};
41 static GENERIC_MAPPING ObpTypeMapping
= {
43 STANDARD_RIGHTS_WRITE
,
44 STANDARD_RIGHTS_EXECUTE
,
49 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo
,
50 PUNICODE_STRING ObjectName
,
51 POBJECT_TYPE ObjectType
,
53 POBJECT_HEADER
*ObjectHeader
);
55 /* FUNCTIONS **************************************************************/
61 ObReferenceObjectByName(PUNICODE_STRING ObjectPath
,
63 PACCESS_STATE PassedAccessState
,
64 ACCESS_MASK DesiredAccess
,
65 POBJECT_TYPE ObjectType
,
66 KPROCESSOR_MODE AccessMode
,
71 UNICODE_STRING RemainingPath
;
72 UNICODE_STRING ObjectName
;
73 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
78 /* Capture the name */
79 DPRINT("Capturing Name\n");
80 Status
= ObpCaptureObjectName(&ObjectName
, ObjectPath
, AccessMode
);
81 if (!NT_SUCCESS(Status
))
83 DPRINT("ObpCaptureObjectName() failed (Status %lx)\n", Status
);
88 * Create a fake ObjectCreateInfo structure. Note that my upcoming
89 * ObFindObject refactoring will remove the need for this hack.
91 ObjectCreateInfo
.RootDirectory
= NULL
;
92 ObjectCreateInfo
.Attributes
= Attributes
;
94 Status
= ObFindObject(&ObjectCreateInfo
,
100 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
102 if (!NT_SUCCESS(Status
))
106 DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath
.Buffer
, Object
);
108 if (RemainingPath
.Buffer
!= NULL
|| Object
== NULL
)
110 DPRINT("Object %p\n", Object
);
112 RtlFreeUnicodeString (&RemainingPath
);
113 return(STATUS_OBJECT_NAME_NOT_FOUND
);
116 RtlFreeUnicodeString (&RemainingPath
);
117 return(STATUS_SUCCESS
);
121 /**********************************************************************
126 * Obtain a handle to an existing object.
150 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes
,
151 IN POBJECT_TYPE ObjectType
,
152 IN OUT PVOID ParseContext
,
153 IN KPROCESSOR_MODE AccessMode
,
154 IN ACCESS_MASK DesiredAccess
,
155 IN PACCESS_STATE PassedAccessState
,
158 UNICODE_STRING RemainingPath
;
160 UNICODE_STRING ObjectName
;
161 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
166 DPRINT("ObOpenObjectByName(...)\n");
168 /* Capture all the info */
169 DPRINT("Capturing Create Info\n");
170 Status
= ObpCaptureObjectAttributes(ObjectAttributes
,
175 if (!NT_SUCCESS(Status
))
177 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
181 Status
= ObFindObject(&ObjectCreateInfo
,
186 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
187 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
188 if (!NT_SUCCESS(Status
))
190 DPRINT("ObFindObject() failed (Status %lx)\n", Status
);
194 DPRINT("OBject: %x, Remaining Path: %wZ\n", Object
, &RemainingPath
);
197 RtlFreeUnicodeString(&RemainingPath
);
198 return STATUS_UNSUCCESSFUL
;
200 if (RemainingPath
.Buffer
!= NULL
)
202 if (wcschr(RemainingPath
.Buffer
+ 1, L
'\\') == NULL
)
203 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
205 Status
=STATUS_OBJECT_PATH_NOT_FOUND
;
206 RtlFreeUnicodeString(&RemainingPath
);
207 ObDereferenceObject(Object
);
211 Status
= ObpCreateHandle(PsGetCurrentProcess(),
217 ObDereferenceObject(Object
);
218 RtlFreeUnicodeString(&RemainingPath
);
225 ObQueryDeviceMapInformation(PEPROCESS Process
,
226 PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
)
231 * FIXME: This is an ugly hack for now, to always return the System Device Map
232 * instead of returning the Process Device Map. Not important yet since we don't use it
235 /* FIXME: Acquire the DeviceMap Spinlock */
236 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
239 DeviceMapInfo
->Query
.DriveMap
= ObSystemDeviceMap
->DriveMap
;
240 RtlMoveMemory(DeviceMapInfo
->Query
.DriveType
, ObSystemDeviceMap
->DriveType
, sizeof(ObSystemDeviceMap
->DriveType
));
242 /* FIXME: Release the DeviceMap Spinlock */
243 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
248 ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent
,
249 POBJECT_HEADER Header
,
252 * FUNCTION: Add an entry to a namespace directory
254 * Parent = directory to add in
255 * Header = Header of the object to add the entry for
256 * Name = Name to give the entry
261 ASSERT(HEADER_TO_OBJECT_NAME(Header
));
262 HEADER_TO_OBJECT_NAME(Header
)->Directory
= Parent
;
264 KeAcquireSpinLock(&Parent
->Lock
, &oldlvl
);
265 InsertTailList(&Parent
->head
, &Header
->Entry
);
266 KeReleaseSpinLock(&Parent
->Lock
, oldlvl
);
272 ObpRemoveEntryDirectory(POBJECT_HEADER Header
)
274 * FUNCTION: Remove an entry from a namespace directory
276 * Header = Header of the object to remove
281 DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header
);
283 KeAcquireSpinLock(&(HEADER_TO_OBJECT_NAME(Header
)->Directory
->Lock
),&oldlvl
);
284 if (Header
->Entry
.Flink
&& Header
->Entry
.Blink
)
286 RemoveEntryList(&(Header
->Entry
));
287 Header
->Entry
.Flink
= Header
->Entry
.Blink
= NULL
;
289 KeReleaseSpinLock(&(HEADER_TO_OBJECT_NAME(Header
)->Directory
->Lock
),oldlvl
);
294 ObpCreateDirectory(OB_OPEN_REASON Reason
,
298 ACCESS_MASK GrantedAccess
)
300 PDIRECTORY_OBJECT Directory
= ObjectBody
;
302 if (Reason
== ObCreateHandle
)
304 InitializeListHead(&Directory
->head
);
305 KeInitializeSpinLock(&Directory
->Lock
);
308 return STATUS_SUCCESS
;
312 ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject
,
316 PLIST_ENTRY current
= DirectoryObject
->head
.Flink
;
317 POBJECT_HEADER current_obj
;
319 DPRINT("ObFindEntryDirectory(dir %x, name %S)\n",DirectoryObject
, Name
);
323 return(DirectoryObject
);
325 if (Name
[0]=='.' && Name
[1]==0)
327 return(DirectoryObject
);
329 if (Name
[0]=='.' && Name
[1]=='.' && Name
[2]==0)
331 return(HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(DirectoryObject
))->Directory
);
333 while (current
!=(&(DirectoryObject
->head
)))
335 current_obj
= CONTAINING_RECORD(current
,OBJECT_HEADER
,Entry
);
336 DPRINT(" Scanning: %S for: %S\n",HEADER_TO_OBJECT_NAME(current_obj
)->Name
.Buffer
, Name
);
337 if (Attributes
& OBJ_CASE_INSENSITIVE
)
339 if (_wcsicmp(HEADER_TO_OBJECT_NAME(current_obj
)->Name
.Buffer
, Name
)==0)
341 DPRINT("Found it %x\n",¤t_obj
->Body
);
342 return(¤t_obj
->Body
);
347 if ( wcscmp(HEADER_TO_OBJECT_NAME(current_obj
)->Name
.Buffer
, Name
)==0)
349 DPRINT("Found it %x\n",¤t_obj
->Body
);
350 return(¤t_obj
->Body
);
353 current
= current
->Flink
;
355 DPRINT(" Not Found: %s() = NULL\n",__FUNCTION__
);
361 ObpParseDirectory(PVOID Object
,
363 PUNICODE_STRING FullPath
,
372 DPRINT("ObpParseDirectory(Object %x, Path %x, *Path %S)\n",
379 return STATUS_UNSUCCESSFUL
;
386 End
= wcschr(Start
, L
'\\');
392 KeAcquireSpinLock(&(((PDIRECTORY_OBJECT
)Object
)->Lock
), &oldlvl
);
393 FoundObject
= ObpFindEntryDirectory(Object
, Start
, Attributes
);
394 if (FoundObject
== NULL
)
396 KeReleaseSpinLock(&(((PDIRECTORY_OBJECT
)Object
)->Lock
), oldlvl
);
401 return STATUS_UNSUCCESSFUL
;
404 ObReferenceObjectByPointer(FoundObject
,
405 STANDARD_RIGHTS_REQUIRED
,
408 KeReleaseSpinLock(&(((PDIRECTORY_OBJECT
)Object
)->Lock
), oldlvl
);
419 *NextObject
= FoundObject
;
421 return STATUS_SUCCESS
;
428 OBJECT_ATTRIBUTES ObjectAttributes
;
430 SECURITY_DESCRIPTOR SecurityDescriptor
;
431 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
433 /* Initialize the security descriptor cache */
436 /* Initialize the Default Event */
437 KeInitializeEvent(&ObpDefaultObject
, NotificationEvent
, TRUE
);
439 /* Create the Type Type */
440 DPRINT("Creating Type Type\n");
441 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
442 RtlInitUnicodeString(&Name
, L
"Type");
443 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
444 ObjectTypeInitializer
.ValidAccessMask
= OBJECT_TYPE_ALL_ACCESS
;
445 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
446 ObjectTypeInitializer
.MaintainTypeList
= TRUE
;
447 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
448 ObjectTypeInitializer
.GenericMapping
= ObpTypeMapping
;
449 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(OBJECT_TYPE
);
450 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObTypeObjectType
);
452 /* Create the Directory Type */
453 DPRINT("Creating Directory Type\n");
454 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
455 RtlInitUnicodeString(&Name
, L
"Directory");
456 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
457 ObjectTypeInitializer
.ValidAccessMask
= DIRECTORY_ALL_ACCESS
;
458 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
459 ObjectTypeInitializer
.OpenProcedure
= ObpCreateDirectory
;
460 ObjectTypeInitializer
.ParseProcedure
= ObpParseDirectory
;
461 ObjectTypeInitializer
.MaintainTypeList
= FALSE
;
462 ObjectTypeInitializer
.GenericMapping
= ObpDirectoryMapping
;
463 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DIRECTORY_OBJECT
);
464 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ObDirectoryType
);
466 /* Create security descriptor */
467 RtlCreateSecurityDescriptor(&SecurityDescriptor
,
468 SECURITY_DESCRIPTOR_REVISION1
);
469 RtlSetOwnerSecurityDescriptor(&SecurityDescriptor
,
472 RtlSetGroupSecurityDescriptor(&SecurityDescriptor
,
475 RtlSetDaclSecurityDescriptor(&SecurityDescriptor
,
480 /* Create root directory */
481 DPRINT("Creating Root Directory\n");
482 InitializeObjectAttributes(&ObjectAttributes
,
486 &SecurityDescriptor
);
487 ObCreateObject(KernelMode
,
492 sizeof(DIRECTORY_OBJECT
),
495 (PVOID
*)&NameSpaceRoot
);
496 ObInsertObject((PVOID
)NameSpaceRoot
,
498 DIRECTORY_ALL_ACCESS
,
503 /* Create '\ObjectTypes' directory */
504 RtlInitUnicodeString(&Name
, L
"\\ObjectTypes");
505 InitializeObjectAttributes(&ObjectAttributes
,
509 &SecurityDescriptor
);
510 ObCreateObject(KernelMode
,
515 sizeof(DIRECTORY_OBJECT
),
518 (PVOID
*)&ObpTypeDirectoryObject
);
519 ObInsertObject((PVOID
)ObpTypeDirectoryObject
,
521 DIRECTORY_ALL_ACCESS
,
526 /* Insert the two objects we already created but couldn't add */
527 /* NOTE: Uses TypeList & Creator Info in OB 2.0 */
528 ObpAddEntryDirectory(ObpTypeDirectoryObject
, BODY_TO_HEADER(ObTypeObjectType
), NULL
);
529 ObpAddEntryDirectory(ObpTypeDirectoryObject
, BODY_TO_HEADER(ObDirectoryType
), NULL
);
531 /* Create 'symbolic link' object type */
532 ObInitSymbolicLinkImplementation();
534 /* FIXME: Hack Hack! */
535 ObSystemDeviceMap
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*ObSystemDeviceMap
), TAG('O', 'b', 'D', 'm'));
536 RtlZeroMemory(ObSystemDeviceMap
, sizeof(*ObSystemDeviceMap
));
541 ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer
,
542 PUNICODE_STRING TypeName
,
543 POBJECT_TYPE
*ObjectType
)
545 POBJECT_HEADER Header
;
546 POBJECT_TYPE LocalObjectType
;
550 DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", TypeName
);
552 /* Allocate the Object */
553 Status
= ObpAllocateObject(NULL
,
556 OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE
)),
558 if (!NT_SUCCESS(Status
))
560 DPRINT1("ObpAllocateObject failed!\n");
564 LocalObjectType
= (POBJECT_TYPE
)&Header
->Body
;
565 DPRINT("Local ObjectType: %p Header: %p \n", LocalObjectType
, Header
);
567 /* Check if this is the first Object Type */
568 if (!ObTypeObjectType
)
570 ObTypeObjectType
= LocalObjectType
;
571 Header
->Type
= ObTypeObjectType
;
572 LocalObjectType
->Key
= TAG('O', 'b', 'j', 'T');
577 Tag
[0] = TypeName
->Buffer
[0];
578 Tag
[1] = TypeName
->Buffer
[1];
579 Tag
[2] = TypeName
->Buffer
[2];
580 Tag
[3] = TypeName
->Buffer
[3];
583 DPRINT("Convert: %s \n", Tag
);
584 LocalObjectType
->Key
= *(PULONG
)Tag
;
588 LocalObjectType
->TypeInfo
= *ObjectTypeInitializer
;
589 LocalObjectType
->Name
= *TypeName
;
590 LocalObjectType
->TypeInfo
.PoolType
= ObjectTypeInitializer
->PoolType
;
592 /* These two flags need to be manually set up */
593 Header
->Flags
|= OB_FLAG_KERNEL_MODE
| OB_FLAG_PERMANENT
;
595 /* Check if we have to maintain a type list */
596 if (NtGlobalFlag
& FLG_MAINTAIN_OBJECT_TYPELIST
)
599 LocalObjectType
->TypeInfo
.MaintainTypeList
= TRUE
;
602 /* Calculate how much space our header'll take up */
603 HeaderSize
= sizeof(OBJECT_HEADER
) + sizeof(OBJECT_HEADER_NAME_INFO
) +
604 (ObjectTypeInitializer
->MaintainHandleCount
?
605 sizeof(OBJECT_HEADER_HANDLE_INFO
) : 0);
607 /* Update the Pool Charges */
608 if (ObjectTypeInitializer
->PoolType
== NonPagedPool
)
610 LocalObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
+= HeaderSize
;
614 LocalObjectType
->TypeInfo
.DefaultPagedPoolCharge
+= HeaderSize
;
617 /* All objects types need a security procedure */
618 if (!ObjectTypeInitializer
->SecurityProcedure
)
620 LocalObjectType
->TypeInfo
.SecurityProcedure
= SeDefaultObjectMethod
;
623 /* Select the Wait Object */
624 if (LocalObjectType
->TypeInfo
.UseDefaultObject
)
626 /* Add the SYNCHRONIZE access mask since it's waitable */
627 LocalObjectType
->TypeInfo
.ValidAccessMask
|= SYNCHRONIZE
;
629 /* Use the "Default Object", a simple event */
630 LocalObjectType
->DefaultObject
= &ObpDefaultObject
;
632 /* Special system objects get an optimized hack so they can be waited on */
633 else if (TypeName
->Length
== 8 && !wcscmp(TypeName
->Buffer
, L
"File"))
635 LocalObjectType
->DefaultObject
= (PVOID
)FIELD_OFFSET(FILE_OBJECT
, Event
);
637 /* FIXME: When LPC stops sucking, add a hack for Waitable Ports */
640 /* No default Object */
641 LocalObjectType
->DefaultObject
= NULL
;
644 /* Initialize Object Type components */
645 ExInitializeResourceLite(&LocalObjectType
->Mutex
);
646 InitializeListHead(&LocalObjectType
->TypeList
);
648 /* Insert it into the Object Directory */
649 if (ObpTypeDirectoryObject
)
651 ObpAddEntryDirectory(ObpTypeDirectoryObject
, Header
, TypeName
->Buffer
);
652 ObReferenceObject(ObpTypeDirectoryObject
);
655 *ObjectType
= LocalObjectType
;