Fix Tag Usage
[reactos.git] / reactos / ntoskrnl / ob / namespc.c
1 /* $Id$
2 *
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
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES ***************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17
18 /* GLOBALS ****************************************************************/
19
20 POBJECT_TYPE ObDirectoryType = NULL;
21 POBJECT_TYPE ObTypeObjectType = NULL;
22
23 PDIRECTORY_OBJECT NameSpaceRoot = NULL;
24 PDIRECTORY_OBJECT ObpTypeDirectoryObject = NULL;
25 /* FIXME: Move this somewhere else once devicemap support is in */
26 PDEVICE_MAP ObSystemDeviceMap = NULL;
27
28
29 static GENERIC_MAPPING ObpDirectoryMapping = {
30 STANDARD_RIGHTS_READ|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
31 STANDARD_RIGHTS_WRITE|DIRECTORY_CREATE_OBJECT|DIRECTORY_CREATE_SUBDIRECTORY,
32 STANDARD_RIGHTS_EXECUTE|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
33 DIRECTORY_ALL_ACCESS};
34
35 static GENERIC_MAPPING ObpTypeMapping = {
36 STANDARD_RIGHTS_READ,
37 STANDARD_RIGHTS_WRITE,
38 STANDARD_RIGHTS_EXECUTE,
39 0x000F0001};
40
41 NTSTATUS
42 STDCALL
43 ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
44 PUNICODE_STRING ObjectName,
45 POBJECT_TYPE ObjectType,
46 ULONG ObjectSize,
47 POBJECT_HEADER *ObjectHeader);
48
49 /* FUNCTIONS **************************************************************/
50
51 /*
52 * @implemented
53 */
54 NTSTATUS STDCALL
55 ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
56 ULONG Attributes,
57 PACCESS_STATE PassedAccessState,
58 ACCESS_MASK DesiredAccess,
59 POBJECT_TYPE ObjectType,
60 KPROCESSOR_MODE AccessMode,
61 PVOID ParseContext,
62 PVOID* ObjectPtr)
63 {
64 PVOID Object = NULL;
65 UNICODE_STRING RemainingPath;
66 UNICODE_STRING ObjectName;
67 OBJECT_ATTRIBUTES ObjectAttributes;
68 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
69 NTSTATUS Status;
70
71 PAGED_CODE();
72
73 InitializeObjectAttributes(&ObjectAttributes,
74 ObjectPath,
75 Attributes | OBJ_OPENIF,
76 NULL,
77 NULL);
78
79 /* Capture all the info */
80 DPRINT("Capturing Create Info\n");
81 Status = ObpCaptureObjectAttributes(&ObjectAttributes,
82 AccessMode,
83 ObjectType,
84 &ObjectCreateInfo,
85 &ObjectName);
86 if (!NT_SUCCESS(Status))
87 {
88 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
89 return Status;
90 }
91
92 Status = ObFindObject(&ObjectCreateInfo,
93 &ObjectName,
94 &Object,
95 &RemainingPath,
96 ObjectType);
97
98 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
99 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
100
101 if (!NT_SUCCESS(Status))
102 {
103 return(Status);
104 }
105 DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object);
106
107 if (RemainingPath.Buffer != NULL || Object == NULL)
108 {
109 DPRINT("Object %p\n", Object);
110 *ObjectPtr = NULL;
111 RtlFreeUnicodeString (&RemainingPath);
112 return(STATUS_OBJECT_NAME_NOT_FOUND);
113 }
114 *ObjectPtr = Object;
115 RtlFreeUnicodeString (&RemainingPath);
116 return(STATUS_SUCCESS);
117 }
118
119
120 /**********************************************************************
121 * NAME EXPORTED
122 * ObOpenObjectByName
123 *
124 * DESCRIPTION
125 * Obtain a handle to an existing object.
126 *
127 * ARGUMENTS
128 * ObjectAttributes
129 * ...
130 * ObjectType
131 * ...
132 * ParseContext
133 * ...
134 * AccessMode
135 * ...
136 * DesiredAccess
137 * ...
138 * PassedAccessState
139 * ...
140 * Handle
141 * Handle to close.
142 *
143 * RETURN VALUE
144 * Status.
145 *
146 * @implemented
147 */
148 NTSTATUS STDCALL
149 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
150 IN POBJECT_TYPE ObjectType,
151 IN OUT PVOID ParseContext,
152 IN KPROCESSOR_MODE AccessMode,
153 IN ACCESS_MASK DesiredAccess,
154 IN PACCESS_STATE PassedAccessState,
155 OUT PHANDLE Handle)
156 {
157 UNICODE_STRING RemainingPath;
158 PVOID Object = NULL;
159 UNICODE_STRING ObjectName;
160 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
161 NTSTATUS Status;
162
163 PAGED_CODE();
164
165 DPRINT("ObOpenObjectByName(...)\n");
166
167 /* Capture all the info */
168 DPRINT("Capturing Create Info\n");
169 Status = ObpCaptureObjectAttributes(ObjectAttributes,
170 AccessMode,
171 ObjectType,
172 &ObjectCreateInfo,
173 &ObjectName);
174 if (!NT_SUCCESS(Status))
175 {
176 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
177 return Status;
178 }
179
180 Status = ObFindObject(&ObjectCreateInfo,
181 &ObjectName,
182 &Object,
183 &RemainingPath,
184 ObjectType);
185 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
186 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
187 if (!NT_SUCCESS(Status))
188 {
189 DPRINT("ObFindObject() failed (Status %lx)\n", Status);
190 return Status;
191 }
192
193 DPRINT("OBject: %x, Remaining Path: %wZ\n", Object, &RemainingPath);
194 if (Object == NULL)
195 {
196 RtlFreeUnicodeString(&RemainingPath);
197 return STATUS_UNSUCCESSFUL;
198 }
199 if (RemainingPath.Buffer != NULL)
200 {
201 if (wcschr(RemainingPath.Buffer + 1, L'\\') == NULL)
202 Status = STATUS_OBJECT_NAME_NOT_FOUND;
203 else
204 Status =STATUS_OBJECT_PATH_NOT_FOUND;
205 RtlFreeUnicodeString(&RemainingPath);
206 ObDereferenceObject(Object);
207 return Status;
208 }
209
210 Status = ObpCreateHandle(PsGetCurrentProcess(),
211 Object,
212 DesiredAccess,
213 FALSE,
214 Handle);
215
216 ObDereferenceObject(Object);
217 RtlFreeUnicodeString(&RemainingPath);
218
219 return Status;
220 }
221
222 VOID
223 STDCALL
224 ObQueryDeviceMapInformation(PEPROCESS Process,
225 PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
226 {
227 //KIRQL OldIrql ;
228
229 /*
230 * FIXME: This is an ugly hack for now, to always return the System Device Map
231 * instead of returning the Process Device Map. Not important yet since we don't use it
232 */
233
234 /* FIXME: Acquire the DeviceMap Spinlock */
235 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
236
237 /* Make a copy */
238 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
239 RtlMoveMemory(DeviceMapInfo->Query.DriveType, ObSystemDeviceMap->DriveType, sizeof(ObSystemDeviceMap->DriveType));
240
241 /* FIXME: Release the DeviceMap Spinlock */
242 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
243 }
244
245 VOID
246 ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent,
247 POBJECT_HEADER Header,
248 PWSTR Name)
249 /*
250 * FUNCTION: Add an entry to a namespace directory
251 * ARGUMENTS:
252 * Parent = directory to add in
253 * Header = Header of the object to add the entry for
254 * Name = Name to give the entry
255 */
256 {
257 KIRQL oldlvl;
258
259 ASSERT(HEADER_TO_OBJECT_NAME(Header));
260 HEADER_TO_OBJECT_NAME(Header)->Directory = Parent;
261
262 KeAcquireSpinLock(&Parent->Lock, &oldlvl);
263 InsertTailList(&Parent->head, &Header->Entry);
264 KeReleaseSpinLock(&Parent->Lock, oldlvl);
265 }
266
267
268 VOID
269 ObpRemoveEntryDirectory(POBJECT_HEADER Header)
270 /*
271 * FUNCTION: Remove an entry from a namespace directory
272 * ARGUMENTS:
273 * Header = Header of the object to remove
274 */
275 {
276 KIRQL oldlvl;
277
278 DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header);
279
280 KeAcquireSpinLock(&(HEADER_TO_OBJECT_NAME(Header)->Directory->Lock),&oldlvl);
281 if (Header->Entry.Flink && Header->Entry.Blink)
282 {
283 RemoveEntryList(&(Header->Entry));
284 Header->Entry.Flink = Header->Entry.Blink = NULL;
285 }
286 KeReleaseSpinLock(&(HEADER_TO_OBJECT_NAME(Header)->Directory->Lock),oldlvl);
287 }
288
289 NTSTATUS
290 STDCALL
291 ObpCreateDirectory(OB_OPEN_REASON Reason,
292 PVOID ObjectBody,
293 PEPROCESS Process,
294 ULONG HandleCount,
295 ACCESS_MASK GrantedAccess)
296 {
297 PDIRECTORY_OBJECT Directory = ObjectBody;
298
299 if (Reason == ObCreateHandle)
300 {
301 InitializeListHead(&Directory->head);
302 KeInitializeSpinLock(&Directory->Lock);
303 }
304
305 return STATUS_SUCCESS;
306 }
307
308 PVOID
309 ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject,
310 PWSTR Name,
311 ULONG Attributes)
312 {
313 PLIST_ENTRY current = DirectoryObject->head.Flink;
314 POBJECT_HEADER current_obj;
315
316 DPRINT("ObFindEntryDirectory(dir %x, name %S)\n",DirectoryObject, Name);
317
318 if (Name[0]==0)
319 {
320 return(DirectoryObject);
321 }
322 if (Name[0]=='.' && Name[1]==0)
323 {
324 return(DirectoryObject);
325 }
326 if (Name[0]=='.' && Name[1]=='.' && Name[2]==0)
327 {
328 return(HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(DirectoryObject))->Directory);
329 }
330 while (current!=(&(DirectoryObject->head)))
331 {
332 current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry);
333 DPRINT(" Scanning: %S for: %S\n",HEADER_TO_OBJECT_NAME(current_obj)->Name.Buffer, Name);
334 if (Attributes & OBJ_CASE_INSENSITIVE)
335 {
336 if (_wcsicmp(HEADER_TO_OBJECT_NAME(current_obj)->Name.Buffer, Name)==0)
337 {
338 DPRINT("Found it %x\n",&current_obj->Body);
339 return(&current_obj->Body);
340 }
341 }
342 else
343 {
344 if ( wcscmp(HEADER_TO_OBJECT_NAME(current_obj)->Name.Buffer, Name)==0)
345 {
346 DPRINT("Found it %x\n",&current_obj->Body);
347 return(&current_obj->Body);
348 }
349 }
350 current = current->Flink;
351 }
352 DPRINT(" Not Found: %s() = NULL\n",__FUNCTION__);
353 return(NULL);
354 }
355
356
357 NTSTATUS STDCALL
358 ObpParseDirectory(PVOID Object,
359 PVOID * NextObject,
360 PUNICODE_STRING FullPath,
361 PWSTR * Path,
362 ULONG Attributes)
363 {
364 PWSTR Start;
365 PWSTR End;
366 PVOID FoundObject;
367
368 DPRINT("ObpParseDirectory(Object %x, Path %x, *Path %S)\n",
369 Object,Path,*Path);
370
371 *NextObject = NULL;
372
373 if ((*Path) == NULL)
374 {
375 return STATUS_UNSUCCESSFUL;
376 }
377
378 Start = *Path;
379 if (*Start == L'\\')
380 Start++;
381
382 End = wcschr(Start, L'\\');
383 if (End != NULL)
384 {
385 *End = 0;
386 }
387
388 FoundObject = ObpFindEntryDirectory(Object, Start, Attributes);
389 if (FoundObject == NULL)
390 {
391 if (End != NULL)
392 {
393 *End = L'\\';
394 }
395 return STATUS_UNSUCCESSFUL;
396 }
397
398 ObReferenceObjectByPointer(FoundObject,
399 STANDARD_RIGHTS_REQUIRED,
400 NULL,
401 UserMode);
402
403 if (End != NULL)
404 {
405 *End = L'\\';
406 *Path = End;
407 }
408 else
409 {
410 *Path = NULL;
411 }
412
413 *NextObject = FoundObject;
414
415 return STATUS_SUCCESS;
416 }
417
418 VOID
419 INIT_FUNCTION
420 ObInit(VOID)
421 {
422 OBJECT_ATTRIBUTES ObjectAttributes;
423 UNICODE_STRING Name;
424 SECURITY_DESCRIPTOR SecurityDescriptor;
425 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
426
427 /* Initialize the security descriptor cache */
428 ObpInitSdCache();
429
430 /* Create the Type Type */
431 DPRINT("Creating Type Type\n");
432 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
433 RtlInitUnicodeString(&Name, L"Type");
434 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
435 ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
436 ObjectTypeInitializer.UseDefaultObject = TRUE;
437 ObjectTypeInitializer.MaintainTypeList = TRUE;
438 ObjectTypeInitializer.PoolType = NonPagedPool;
439 ObjectTypeInitializer.GenericMapping = ObpTypeMapping;
440 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE);
441 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObTypeObjectType);
442
443 /* Create the Directory Type */
444 DPRINT("Creating Directory Type\n");
445 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
446 RtlInitUnicodeString(&Name, L"Directory");
447 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
448 ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS;
449 ObjectTypeInitializer.UseDefaultObject = FALSE;
450 ObjectTypeInitializer.OpenProcedure = ObpCreateDirectory;
451 ObjectTypeInitializer.ParseProcedure = ObpParseDirectory;
452 ObjectTypeInitializer.MaintainTypeList = FALSE;
453 ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping;
454 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DIRECTORY_OBJECT);
455 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObDirectoryType);
456
457 /* Create security descriptor */
458 RtlCreateSecurityDescriptor(&SecurityDescriptor,
459 SECURITY_DESCRIPTOR_REVISION1);
460 RtlSetOwnerSecurityDescriptor(&SecurityDescriptor,
461 SeAliasAdminsSid,
462 FALSE);
463 RtlSetGroupSecurityDescriptor(&SecurityDescriptor,
464 SeLocalSystemSid,
465 FALSE);
466 RtlSetDaclSecurityDescriptor(&SecurityDescriptor,
467 TRUE,
468 SePublicDefaultDacl,
469 FALSE);
470
471 /* Create root directory */
472 DPRINT("Creating Root Directory\n");
473 InitializeObjectAttributes(&ObjectAttributes,
474 NULL,
475 OBJ_PERMANENT,
476 NULL,
477 &SecurityDescriptor);
478 ObCreateObject(KernelMode,
479 ObDirectoryType,
480 &ObjectAttributes,
481 KernelMode,
482 NULL,
483 sizeof(DIRECTORY_OBJECT),
484 0,
485 0,
486 (PVOID*)&NameSpaceRoot);
487 ObInsertObject((PVOID)NameSpaceRoot,
488 NULL,
489 DIRECTORY_ALL_ACCESS,
490 0,
491 NULL,
492 NULL);
493
494 /* Create '\ObjectTypes' directory */
495 RtlInitUnicodeString(&Name, L"\\ObjectTypes");
496 InitializeObjectAttributes(&ObjectAttributes,
497 &Name,
498 OBJ_PERMANENT,
499 NULL,
500 &SecurityDescriptor);
501 ObCreateObject(KernelMode,
502 ObDirectoryType,
503 &ObjectAttributes,
504 KernelMode,
505 NULL,
506 sizeof(DIRECTORY_OBJECT),
507 0,
508 0,
509 (PVOID*)&ObpTypeDirectoryObject);
510 ObInsertObject((PVOID)ObpTypeDirectoryObject,
511 NULL,
512 DIRECTORY_ALL_ACCESS,
513 0,
514 NULL,
515 NULL);
516
517 /* Insert the two objects we already created but couldn't add */
518 /* NOTE: Uses TypeList & Creator Info in OB 2.0 */
519 ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObTypeObjectType), NULL);
520 ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObDirectoryType), NULL);
521
522 /* Create 'symbolic link' object type */
523 ObInitSymbolicLinkImplementation();
524
525 /* FIXME: Hack Hack! */
526 ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ObSystemDeviceMap), TAG('O', 'b', 'D', 'm'));
527 RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap));
528 }
529
530 NTSTATUS
531 STDCALL
532 ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
533 PUNICODE_STRING TypeName,
534 POBJECT_TYPE *ObjectType)
535 {
536 POBJECT_HEADER Header;
537 POBJECT_TYPE LocalObjectType;
538 NTSTATUS Status;
539
540 DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", TypeName);
541
542 /* Allocate the Object */
543 Status = ObpAllocateObject(NULL,
544 TypeName,
545 ObTypeObjectType,
546 OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE)),
547 &Header);
548 if (!NT_SUCCESS(Status))
549 {
550 DPRINT1("ObpAllocateObject failed!\n");
551 return Status;
552 }
553
554 LocalObjectType = (POBJECT_TYPE)&Header->Body;
555 DPRINT("Local ObjectType: %p Header: %p \n", LocalObjectType, Header);
556
557 /* Check if this is the first Object Type */
558 if (!ObTypeObjectType)
559 {
560 ObTypeObjectType = LocalObjectType;
561 Header->Type = ObTypeObjectType;
562 LocalObjectType->Key = TAG('O', 'b', 'j', 'T');
563 }
564 else
565 {
566 CHAR Tag[4];
567 Tag[0] = TypeName->Buffer[0];
568 Tag[1] = TypeName->Buffer[1];
569 Tag[2] = TypeName->Buffer[2];
570 Tag[3] = TypeName->Buffer[3];
571
572 /* Set Tag */
573 DPRINT1("Convert: %s \n", Tag);
574 LocalObjectType->Key = *(PULONG)Tag;
575 }
576
577 /* Set it up */
578 LocalObjectType->TypeInfo = *ObjectTypeInitializer;
579 LocalObjectType->Name = *TypeName;
580
581 /* Insert it into the Object Directory */
582 if (ObpTypeDirectoryObject)
583 {
584 ObpAddEntryDirectory(ObpTypeDirectoryObject, Header, TypeName->Buffer);
585 ObReferenceObject(ObpTypeDirectoryObject);
586 }
587
588 *ObjectType = LocalObjectType;
589 return Status;
590 }
591
592 /* EOF */