Implement IoRegisterPlugPlayNotification, IoUnregisterPlugPlayNotification
[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 /* FIXME: Move this somewhere else once devicemap support is in */
25 PDEVICE_MAP ObSystemDeviceMap = NULL;
26
27 static GENERIC_MAPPING ObpDirectoryMapping = {
28 STANDARD_RIGHTS_READ|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
29 STANDARD_RIGHTS_WRITE|DIRECTORY_CREATE_OBJECT|DIRECTORY_CREATE_SUBDIRECTORY,
30 STANDARD_RIGHTS_EXECUTE|DIRECTORY_QUERY|DIRECTORY_TRAVERSE,
31 DIRECTORY_ALL_ACCESS};
32
33 static GENERIC_MAPPING ObpTypeMapping = {
34 STANDARD_RIGHTS_READ,
35 STANDARD_RIGHTS_WRITE,
36 STANDARD_RIGHTS_EXECUTE,
37 0x000F0001};
38
39 /* FUNCTIONS **************************************************************/
40
41 /*
42 * @implemented
43 */
44 NTSTATUS STDCALL
45 ObReferenceObjectByName(PUNICODE_STRING ObjectPath,
46 ULONG Attributes,
47 PACCESS_STATE PassedAccessState,
48 ACCESS_MASK DesiredAccess,
49 POBJECT_TYPE ObjectType,
50 KPROCESSOR_MODE AccessMode,
51 PVOID ParseContext,
52 PVOID* ObjectPtr)
53 {
54 PVOID Object = NULL;
55 UNICODE_STRING RemainingPath;
56 OBJECT_ATTRIBUTES ObjectAttributes;
57 NTSTATUS Status;
58
59 PAGED_CODE();
60
61 InitializeObjectAttributes(&ObjectAttributes,
62 ObjectPath,
63 Attributes | OBJ_OPENIF,
64 NULL,
65 NULL);
66 Status = ObFindObject(&ObjectAttributes,
67 &Object,
68 &RemainingPath,
69 ObjectType);
70 if (!NT_SUCCESS(Status))
71 {
72 return(Status);
73 }
74 CHECKPOINT;
75 DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object);
76
77 if (RemainingPath.Buffer != NULL || Object == NULL)
78 {
79 CHECKPOINT;
80 DPRINT("Object %p\n", Object);
81 *ObjectPtr = NULL;
82 RtlFreeUnicodeString (&RemainingPath);
83 return(STATUS_OBJECT_NAME_NOT_FOUND);
84 }
85 *ObjectPtr = Object;
86 RtlFreeUnicodeString (&RemainingPath);
87 return(STATUS_SUCCESS);
88 }
89
90
91 /**********************************************************************
92 * NAME EXPORTED
93 * ObOpenObjectByName
94 *
95 * DESCRIPTION
96 * Obtain a handle to an existing object.
97 *
98 * ARGUMENTS
99 * ObjectAttributes
100 * ...
101 * ObjectType
102 * ...
103 * ParseContext
104 * ...
105 * AccessMode
106 * ...
107 * DesiredAccess
108 * ...
109 * PassedAccessState
110 * ...
111 * Handle
112 * Handle to close.
113 *
114 * RETURN VALUE
115 * Status.
116 *
117 * @implemented
118 */
119 NTSTATUS STDCALL
120 ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
121 IN POBJECT_TYPE ObjectType,
122 IN OUT PVOID ParseContext,
123 IN KPROCESSOR_MODE AccessMode,
124 IN ACCESS_MASK DesiredAccess,
125 IN PACCESS_STATE PassedAccessState,
126 OUT PHANDLE Handle)
127 {
128 UNICODE_STRING RemainingPath;
129 PVOID Object = NULL;
130 NTSTATUS Status;
131
132 PAGED_CODE();
133
134 DPRINT("ObOpenObjectByName(...)\n");
135
136 Status = ObFindObject(ObjectAttributes,
137 &Object,
138 &RemainingPath,
139 ObjectType);
140 if (!NT_SUCCESS(Status))
141 {
142 DPRINT("ObFindObject() failed (Status %lx)\n", Status);
143 return Status;
144 }
145
146 if (RemainingPath.Buffer != NULL ||
147 Object == NULL)
148 {
149 RtlFreeUnicodeString(&RemainingPath);
150 return STATUS_OBJECT_NAME_INVALID;
151 }
152
153 Status = ObCreateHandle(PsGetCurrentProcess(),
154 Object,
155 DesiredAccess,
156 FALSE,
157 Handle);
158
159 ObDereferenceObject(Object);
160 RtlFreeUnicodeString(&RemainingPath);
161
162 return Status;
163 }
164
165 VOID
166 STDCALL
167 ObQueryDeviceMapInformation(PEPROCESS Process,
168 PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
169 {
170 //KIRQL OldIrql ;
171
172 /*
173 * FIXME: This is an ugly hack for now, to always return the System Device Map
174 * instead of returning the Process Device Map. Not important yet since we don't use it
175 */
176
177 /* FIXME: Acquire the DeviceMap Spinlock */
178 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
179
180 /* Make a copy */
181 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
182 RtlMoveMemory(DeviceMapInfo->Query.DriveType, ObSystemDeviceMap->DriveType, sizeof(ObSystemDeviceMap->DriveType));
183
184 /* FIXME: Release the DeviceMap Spinlock */
185 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
186 }
187
188 VOID
189 ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent,
190 POBJECT_HEADER Header,
191 PWSTR Name)
192 /*
193 * FUNCTION: Add an entry to a namespace directory
194 * ARGUMENTS:
195 * Parent = directory to add in
196 * Header = Header of the object to add the entry for
197 * Name = Name to give the entry
198 */
199 {
200 KIRQL oldlvl;
201
202 RtlpCreateUnicodeString(&Header->Name, Name, NonPagedPool);
203 Header->Parent = Parent;
204
205 KeAcquireSpinLock(&Parent->Lock, &oldlvl);
206 InsertTailList(&Parent->head, &Header->Entry);
207 KeReleaseSpinLock(&Parent->Lock, oldlvl);
208 }
209
210
211 VOID
212 ObpRemoveEntryDirectory(POBJECT_HEADER Header)
213 /*
214 * FUNCTION: Remove an entry from a namespace directory
215 * ARGUMENTS:
216 * Header = Header of the object to remove
217 */
218 {
219 KIRQL oldlvl;
220
221 DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header);
222
223 KeAcquireSpinLock(&(Header->Parent->Lock),&oldlvl);
224 if (Header->Entry.Flink && Header->Entry.Blink)
225 {
226 RemoveEntryList(&(Header->Entry));
227 Header->Entry.Flink = Header->Entry.Blink = NULL;
228 }
229 KeReleaseSpinLock(&(Header->Parent->Lock),oldlvl);
230 }
231
232
233 PVOID
234 ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject,
235 PWSTR Name,
236 ULONG Attributes)
237 {
238 PLIST_ENTRY current = DirectoryObject->head.Flink;
239 POBJECT_HEADER current_obj;
240
241 DPRINT("ObFindEntryDirectory(dir %x, name %S)\n",DirectoryObject, Name);
242
243 if (Name[0]==0)
244 {
245 return(DirectoryObject);
246 }
247 if (Name[0]=='.' && Name[1]==0)
248 {
249 return(DirectoryObject);
250 }
251 if (Name[0]=='.' && Name[1]=='.' && Name[2]==0)
252 {
253 return(BODY_TO_HEADER(DirectoryObject)->Parent);
254 }
255 while (current!=(&(DirectoryObject->head)))
256 {
257 current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry);
258 DPRINT(" Scanning: %S for: %S\n",current_obj->Name.Buffer, Name);
259 if (Attributes & OBJ_CASE_INSENSITIVE)
260 {
261 if (_wcsicmp(current_obj->Name.Buffer, Name)==0)
262 {
263 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
264 return(HEADER_TO_BODY(current_obj));
265 }
266 }
267 else
268 {
269 if ( wcscmp(current_obj->Name.Buffer, Name)==0)
270 {
271 DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj));
272 return(HEADER_TO_BODY(current_obj));
273 }
274 }
275 current = current->Flink;
276 }
277 DPRINT(" Not Found: %s() = NULL\n",__FUNCTION__);
278 return(NULL);
279 }
280
281
282 NTSTATUS STDCALL
283 ObpParseDirectory(PVOID Object,
284 PVOID * NextObject,
285 PUNICODE_STRING FullPath,
286 PWSTR * Path,
287 ULONG Attributes)
288 {
289 PWSTR Start;
290 PWSTR End;
291 PVOID FoundObject;
292
293 DPRINT("ObpParseDirectory(Object %x, Path %x, *Path %S)\n",
294 Object,Path,*Path);
295
296 *NextObject = NULL;
297
298 if ((*Path) == NULL)
299 {
300 return STATUS_UNSUCCESSFUL;
301 }
302
303 Start = *Path;
304 if (*Start == L'\\')
305 Start++;
306
307 End = wcschr(Start, L'\\');
308 if (End != NULL)
309 {
310 *End = 0;
311 }
312
313 FoundObject = ObpFindEntryDirectory(Object, Start, Attributes);
314 if (FoundObject == NULL)
315 {
316 if (End != NULL)
317 {
318 *End = L'\\';
319 }
320 return STATUS_UNSUCCESSFUL;
321 }
322
323 ObReferenceObjectByPointer(FoundObject,
324 STANDARD_RIGHTS_REQUIRED,
325 NULL,
326 UserMode);
327
328 if (End != NULL)
329 {
330 *End = L'\\';
331 *Path = End;
332 }
333 else
334 {
335 *Path = NULL;
336 }
337
338 *NextObject = FoundObject;
339
340 return STATUS_SUCCESS;
341 }
342
343
344 NTSTATUS STDCALL
345 ObpCreateDirectory(PVOID ObjectBody,
346 PVOID Parent,
347 PWSTR RemainingPath,
348 POBJECT_ATTRIBUTES ObjectAttributes)
349 {
350 PDIRECTORY_OBJECT DirectoryObject = (PDIRECTORY_OBJECT)ObjectBody;
351
352 DPRINT("ObpCreateDirectory(ObjectBody %x, Parent %x, RemainingPath %S)\n",
353 ObjectBody, Parent, RemainingPath);
354
355 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
356 {
357 return(STATUS_UNSUCCESSFUL);
358 }
359
360 InitializeListHead(&DirectoryObject->head);
361 KeInitializeSpinLock(&DirectoryObject->Lock);
362
363 return(STATUS_SUCCESS);
364 }
365
366
367 VOID INIT_FUNCTION
368 ObInit(VOID)
369 /*
370 * FUNCTION: Initialize the object manager namespace
371 */
372 {
373 OBJECT_ATTRIBUTES ObjectAttributes;
374 UNICODE_STRING Name;
375 SECURITY_DESCRIPTOR SecurityDescriptor;
376
377 /* Initialize the security descriptor cache */
378 ObpInitSdCache();
379
380 /* create 'directory' object type */
381 ObDirectoryType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
382
383 ObDirectoryType->Tag = TAG('D', 'I', 'R', 'T');
384 ObDirectoryType->TotalObjects = 0;
385 ObDirectoryType->TotalHandles = 0;
386 ObDirectoryType->PeakObjects = 0;
387 ObDirectoryType->PeakHandles = 0;
388 ObDirectoryType->PagedPoolCharge = 0;
389 ObDirectoryType->NonpagedPoolCharge = sizeof(DIRECTORY_OBJECT);
390 ObDirectoryType->Mapping = &ObpDirectoryMapping;
391 ObDirectoryType->Dump = NULL;
392 ObDirectoryType->Open = NULL;
393 ObDirectoryType->Close = NULL;
394 ObDirectoryType->Delete = NULL;
395 ObDirectoryType->Parse = ObpParseDirectory;
396 ObDirectoryType->Security = NULL;
397 ObDirectoryType->QueryName = NULL;
398 ObDirectoryType->OkayToClose = NULL;
399 ObDirectoryType->Create = ObpCreateDirectory;
400 ObDirectoryType->DuplicationNotify = NULL;
401
402 RtlInitUnicodeString(&ObDirectoryType->TypeName,
403 L"Directory");
404
405 /* create 'type' object type*/
406 ObTypeObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
407
408 ObTypeObjectType->Tag = TAG('T', 'y', 'p', 'T');
409 ObTypeObjectType->TotalObjects = 0;
410 ObTypeObjectType->TotalHandles = 0;
411 ObTypeObjectType->PeakObjects = 0;
412 ObTypeObjectType->PeakHandles = 0;
413 ObTypeObjectType->PagedPoolCharge = 0;
414 ObTypeObjectType->NonpagedPoolCharge = sizeof(TYPE_OBJECT);
415 ObTypeObjectType->Mapping = &ObpTypeMapping;
416 ObTypeObjectType->Dump = NULL;
417 ObTypeObjectType->Open = NULL;
418 ObTypeObjectType->Close = NULL;
419 ObTypeObjectType->Delete = NULL;
420 ObTypeObjectType->Parse = NULL;
421 ObTypeObjectType->Security = NULL;
422 ObTypeObjectType->QueryName = NULL;
423 ObTypeObjectType->OkayToClose = NULL;
424 ObTypeObjectType->Create = NULL;
425 ObTypeObjectType->DuplicationNotify = NULL;
426
427 RtlInitUnicodeString(&ObTypeObjectType->TypeName,
428 L"ObjectType");
429
430 /* Create security descriptor */
431 RtlCreateSecurityDescriptor(&SecurityDescriptor,
432 SECURITY_DESCRIPTOR_REVISION1);
433
434 RtlSetOwnerSecurityDescriptor(&SecurityDescriptor,
435 SeAliasAdminsSid,
436 FALSE);
437
438 RtlSetGroupSecurityDescriptor(&SecurityDescriptor,
439 SeLocalSystemSid,
440 FALSE);
441
442 RtlSetDaclSecurityDescriptor(&SecurityDescriptor,
443 TRUE,
444 SePublicDefaultDacl,
445 FALSE);
446
447 /* Create root directory */
448 InitializeObjectAttributes(&ObjectAttributes,
449 NULL,
450 OBJ_PERMANENT,
451 NULL,
452 &SecurityDescriptor);
453 ObCreateObject(KernelMode,
454 ObDirectoryType,
455 &ObjectAttributes,
456 KernelMode,
457 NULL,
458 sizeof(DIRECTORY_OBJECT),
459 0,
460 0,
461 (PVOID*)&NameSpaceRoot);
462
463 /* Create '\ObjectTypes' directory */
464 RtlRosInitUnicodeStringFromLiteral(&Name,
465 L"\\ObjectTypes");
466 InitializeObjectAttributes(&ObjectAttributes,
467 &Name,
468 OBJ_PERMANENT,
469 NULL,
470 &SecurityDescriptor);
471 ObCreateObject(KernelMode,
472 ObDirectoryType,
473 &ObjectAttributes,
474 KernelMode,
475 NULL,
476 sizeof(DIRECTORY_OBJECT),
477 0,
478 0,
479 NULL);
480
481 ObpCreateTypeObject(ObDirectoryType);
482 ObpCreateTypeObject(ObTypeObjectType);
483
484 /* Create 'symbolic link' object type */
485 ObInitSymbolicLinkImplementation();
486
487 /* FIXME: Hack Hack! */
488 ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ObSystemDeviceMap), TAG('O', 'b', 'D', 'm'));
489 RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap));
490 }
491
492
493 NTSTATUS
494 ObpCreateTypeObject(POBJECT_TYPE ObjectType)
495 {
496 OBJECT_ATTRIBUTES ObjectAttributes;
497 WCHAR NameString[120];
498 PTYPE_OBJECT TypeObject = NULL;
499 UNICODE_STRING Name;
500 NTSTATUS Status;
501
502 DPRINT("ObpCreateTypeObject(ObjectType: %wZ)\n", &ObjectType->TypeName);
503 wcscpy(NameString, L"\\ObjectTypes\\");
504 wcscat(NameString, ObjectType->TypeName.Buffer);
505 RtlInitUnicodeString(&Name,
506 NameString);
507
508 InitializeObjectAttributes(&ObjectAttributes,
509 &Name,
510 OBJ_PERMANENT,
511 NULL,
512 NULL);
513 Status = ObCreateObject(KernelMode,
514 ObTypeObjectType,
515 &ObjectAttributes,
516 KernelMode,
517 NULL,
518 sizeof(TYPE_OBJECT),
519 0,
520 0,
521 (PVOID*)&TypeObject);
522 if (NT_SUCCESS(Status))
523 {
524 TypeObject->ObjectType = ObjectType;
525 }
526
527 return(STATUS_SUCCESS);
528 }
529
530 /* EOF */