Merge 25584, 25588.
[reactos.git] / reactos / ntoskrnl / ob / obname.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/namespce.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)
8 * Eric Kohl
9 * Thomas Weidenmueller (w3seek@reactos.org)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #define NTDDI_VERSION NTDDI_WINXP
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 POBJECT_DIRECTORY NameSpaceRoot = NULL;
20 POBJECT_DIRECTORY ObpTypeDirectoryObject = NULL;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 NTSTATUS
25 NTAPI
26 ObpCreateDosDevicesDirectory(VOID)
27 {
28 OBJECT_ATTRIBUTES ObjectAttributes;
29 UNICODE_STRING Name, LinkName;
30 HANDLE Handle, SymHandle;
31 NTSTATUS Status;
32
33 /* Create the '\??' directory */
34 RtlInitUnicodeString(&Name, L"\\??");
35 InitializeObjectAttributes(&ObjectAttributes,
36 &Name,
37 OBJ_PERMANENT,
38 NULL,
39 NULL);
40 Status = NtCreateDirectoryObject(&Handle,
41 DIRECTORY_ALL_ACCESS,
42 &ObjectAttributes);
43 if (!NT_SUCCESS(Status)) return FALSE;
44
45 /* Initialize the GLOBALROOT path */
46 RtlInitUnicodeString(&LinkName, L"GLOBALROOT");
47 RtlInitUnicodeString(&Name, L"");
48 InitializeObjectAttributes(&ObjectAttributes,
49 &LinkName,
50 OBJ_PERMANENT,
51 Handle,
52 NULL);
53 Status = NtCreateSymbolicLinkObject(&SymHandle,
54 SYMBOLIC_LINK_ALL_ACCESS,
55 &ObjectAttributes,
56 &Name);
57 if (NT_SUCCESS(Status)) NtClose(SymHandle);
58
59 /* Link \??\Global to \?? */
60 RtlInitUnicodeString(&LinkName, L"Global");
61 RtlInitUnicodeString(&Name, L"\\??");
62 InitializeObjectAttributes(&ObjectAttributes,
63 &LinkName,
64 OBJ_PERMANENT,
65 Handle,
66 NULL);
67 Status = NtCreateSymbolicLinkObject(&SymHandle,
68 SYMBOLIC_LINK_ALL_ACCESS,
69 &ObjectAttributes,
70 &Name);
71 if (NT_SUCCESS(Status)) NtClose(SymHandle);
72
73 /* Close the directory handle */
74 NtClose(Handle);
75 if (!NT_SUCCESS(Status)) return Status;
76
77 /* Create link from '\DosDevices' to '\??' directory */
78 RtlCreateUnicodeString(&LinkName, L"\\DosDevices");
79 InitializeObjectAttributes(&ObjectAttributes,
80 &LinkName,
81 OBJ_PERMANENT,
82 NULL,
83 NULL);
84 Status = NtCreateSymbolicLinkObject(&SymHandle,
85 SYMBOLIC_LINK_ALL_ACCESS,
86 &ObjectAttributes,
87 &Name);
88 if (NT_SUCCESS(Status)) NtClose(SymHandle);
89
90 /* FIXME: Hack Hack! */
91 ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool,
92 sizeof(*ObSystemDeviceMap),
93 TAG('O', 'b', 'D', 'm'));
94 RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap));
95
96 /* Return status */
97 return Status;
98 }
99
100 VOID
101 NTAPI
102 ObDereferenceDeviceMap(IN PEPROCESS Process)
103 {
104 //KIRQL OldIrql;
105 PDEVICE_MAP DeviceMap = Process->DeviceMap;
106
107 /* FIXME: We don't use Process Devicemaps yet */
108 if (DeviceMap)
109 {
110 /* FIXME: Acquire the DeviceMap Spinlock */
111 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
112
113 /* Delete the device map link and dereference it */
114 Process->DeviceMap = NULL;
115 if (--DeviceMap->ReferenceCount)
116 {
117 /* Nobody is referencing it anymore, unlink the DOS directory */
118 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
119
120 /* FIXME: Release the DeviceMap Spinlock */
121 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
122
123 /* Dereference the DOS Devices Directory and free the Device Map */
124 ObDereferenceObject(DeviceMap->DosDevicesDirectory);
125 ExFreePool(DeviceMap);
126 }
127 else
128 {
129 /* FIXME: Release the DeviceMap Spinlock */
130 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
131 }
132 }
133 }
134
135 VOID
136 NTAPI
137 ObInheritDeviceMap(IN PEPROCESS Parent,
138 IN PEPROCESS Process)
139 {
140 /* FIXME: Devicemap Support */
141 }
142
143 /*++
144 * @name ObpDeleteNameCheck
145 *
146 * The ObpDeleteNameCheck routine checks if a named object should be
147 * removed from the object directory namespace.
148 *
149 * @param Object
150 * Pointer to the object to check for possible removal.
151 *
152 * @return None.
153 *
154 * @remarks An object is removed if the following 4 criteria are met:
155 * 1) The object has 0 handles open
156 * 2) The object is in the directory namespace and has a name
157 * 3) The object is not permanent
158 *
159 *--*/
160 VOID
161 NTAPI
162 ObpDeleteNameCheck(IN PVOID Object)
163 {
164 POBJECT_HEADER ObjectHeader;
165 OBP_LOOKUP_CONTEXT Context;
166 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
167 POBJECT_TYPE ObjectType;
168 PVOID Directory = NULL;
169
170 /* Get object structures */
171 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
172 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
173 ObjectType = ObjectHeader->Type;
174
175 /*
176 * Check if the handle count is 0, if the object is named,
177 * and if the object isn't a permanent object.
178 */
179 if (!(ObjectHeader->HandleCount) &&
180 (ObjectNameInfo) &&
181 (ObjectNameInfo->Name.Length) &&
182 !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
183 {
184 /* Make sure it's still inserted */
185 Context.Directory = ObjectNameInfo->Directory;
186 Context.DirectoryLocked = TRUE;
187 Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory,
188 &ObjectNameInfo->Name,
189 0,
190 FALSE,
191 &Context);
192 if ((Object) && !(ObjectHeader->HandleCount))
193 {
194 /* Lock the object type */
195 ObpEnterObjectTypeMutex(ObjectType);
196
197 /* First delete it from the directory */
198 ObpDeleteEntryDirectory(&Context);
199
200 /* Now check if we have a security callback */
201 if (ObjectType->TypeInfo.SecurityRequired)
202 {
203 /* Call it */
204 ObjectType->TypeInfo.SecurityProcedure(Object,
205 DeleteSecurityDescriptor,
206 0,
207 NULL,
208 NULL,
209 &ObjectHeader->
210 SecurityDescriptor,
211 ObjectType->
212 TypeInfo.PoolType,
213 NULL);
214 }
215
216 /* Release the lock */
217 ObpLeaveObjectTypeMutex(ObjectType);
218
219 /* Free the name */
220 ExFreePool(ObjectNameInfo->Name.Buffer);
221 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
222
223 /* Clear the current directory and de-reference it */
224 Directory = ObjectNameInfo->Directory;
225 ObjectNameInfo->Directory = NULL;
226 }
227
228 /* Check if we were inserted in a directory */
229 if (Directory)
230 {
231 /* We were, so dereference the directory and the object as well */
232 ObDereferenceObject(Directory);
233 ObDereferenceObject(Object);
234 }
235 }
236 }
237
238 NTSTATUS
239 NTAPI
240 ObFindObject(IN HANDLE RootHandle,
241 IN PUNICODE_STRING ObjectName,
242 IN ULONG Attributes,
243 IN KPROCESSOR_MODE AccessMode,
244 IN PVOID *ReturnedObject,
245 IN POBJECT_TYPE ObjectType,
246 IN POBP_LOOKUP_CONTEXT Context,
247 IN PACCESS_STATE AccessState,
248 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
249 IN OUT PVOID ParseContext,
250 OUT PVOID ExpectedObject)
251 {
252 PVOID RootDirectory;
253 PVOID CurrentDirectory = NULL;
254 PVOID CurrentObject = NULL;
255 POBJECT_HEADER CurrentHeader;
256 NTSTATUS Status = STATUS_SUCCESS;
257 PVOID NewName;
258 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
259 UNICODE_STRING RemainingPath, PartName;
260 BOOLEAN InsideRoot = FALSE;
261 OB_PARSE_METHOD ParseRoutine;
262 PAGED_CODE();
263
264 /* Assume failure */
265 OBTRACE(OB_NAMESPACE_DEBUG,
266 "%s - Finding Object: %wZ. Expecting: %p\n",
267 __FUNCTION__,
268 ObjectName,
269 ExpectedObject);
270 *ReturnedObject = NULL;
271
272 /* Check if we got a Root Directory */
273 if (RootHandle)
274 {
275 /* We did. Reference it */
276 Status = ObReferenceObjectByHandle(RootHandle,
277 0,
278 NULL,
279 AccessMode,
280 &RootDirectory,
281 NULL);
282 if (!NT_SUCCESS(Status)) return Status;
283
284 /* Get the header */
285 CurrentHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
286
287 /* The name cannot start with a separator, unless this is a file */
288 if ((ObjectName->Buffer) &&
289 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
290 (CurrentHeader->Type != IoFileObjectType))
291 {
292 /* The syntax is bad, so fail this request */
293 ObDereferenceObject(RootDirectory);
294 return STATUS_OBJECT_PATH_SYNTAX_BAD;
295 }
296
297 /* Don't parse a Directory */
298 if (CurrentHeader->Type != ObDirectoryType)
299 {
300 /* Make sure the Object Type has a parse routine */
301 ParseRoutine = CurrentHeader->Type->TypeInfo.ParseProcedure;
302 if (!ParseRoutine)
303 {
304 /* We can't parse a name if we don't have a parse routine */
305 ObDereferenceObject(RootDirectory);
306 return STATUS_INVALID_HANDLE;
307 }
308
309 /* Now parse */
310 while (TRUE)
311 {
312 /* Start with the full name */
313 RemainingPath = *ObjectName;
314
315 /* Call the Parse Procedure */
316 Status = ParseRoutine(RootDirectory,
317 ObjectType,
318 AccessState,
319 AccessMode,
320 Attributes,
321 ObjectName,
322 &RemainingPath,
323 ParseContext,
324 SecurityQos,
325 &CurrentObject);
326
327 /* Check for success or failure, so not reparse */
328 if ((Status != STATUS_REPARSE) &&
329 (Status != STATUS_REPARSE_OBJECT))
330 {
331 /* Check for failure */
332 if (!NT_SUCCESS(Status))
333 {
334 /* Parse routine might not have cleared this, do it */
335 CurrentObject = NULL;
336 }
337 else if (!CurrentObject)
338 {
339 /* Modify status to reflect failure inside Ob */
340 Status = STATUS_OBJECT_NAME_NOT_FOUND;
341 }
342
343 /* We're done, return the status and object */
344 *ReturnedObject = CurrentObject;
345 ObDereferenceObject(RootDirectory);
346 return Status;
347 }
348 else if ((!ObjectName->Length) ||
349 (!ObjectName->Buffer) ||
350 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
351 {
352 /* Reparsed to the root directory, so start over */
353 ObDereferenceObject(RootDirectory);
354 RootDirectory = NameSpaceRoot;
355
356 /* Don't use this anymore, since we're starting at root */
357 RootHandle = NULL;
358 break;
359 }
360 }
361 }
362 else if (!(ObjectName->Length) || !(ObjectName->Buffer))
363 {
364 /* Just return the Root Directory if we didn't get a name*/
365 Status = ObReferenceObjectByPointer(RootDirectory,
366 0,
367 ObjectType,
368 AccessMode);
369 if (NT_SUCCESS(Status)) *ReturnedObject = RootDirectory;
370 ObDereferenceObject(RootDirectory);
371 return Status;
372 }
373 }
374 else
375 {
376 /* We did not get a Root Directory, so use the root */
377 RootDirectory = NameSpaceRoot;
378
379 /* It must start with a path separator */
380 if (!(ObjectName->Length) ||
381 !(ObjectName->Buffer) ||
382 (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR))
383 {
384 /* This name is invalid, so fail */
385 return STATUS_OBJECT_PATH_SYNTAX_BAD;
386 }
387
388 /* Check if the name is only the path separator */
389 if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR))
390 {
391 /* So the caller only wants the root directory; do we have one? */
392 if (!RootDirectory)
393 {
394 /* This must be the first time we're creating it... right? */
395 if (ExpectedObject)
396 {
397 /* Yes, so return it to ObInsert so that it can create it */
398 Status = ObReferenceObjectByPointer(ExpectedObject,
399 0,
400 ObjectType,
401 AccessMode);
402 if (NT_SUCCESS(Status)) *ReturnedObject = ExpectedObject;
403 return Status;
404 }
405 else
406 {
407 /* This should never really happen */
408 ASSERT(FALSE);
409 return STATUS_INVALID_PARAMETER;
410 }
411 }
412 else
413 {
414 /* We do have the root directory, so just return it */
415 Status = ObReferenceObjectByPointer(RootDirectory,
416 0,
417 ObjectType,
418 AccessMode);
419 if (NT_SUCCESS(Status)) *ReturnedObject = RootDirectory;
420 return Status;
421 }
422 }
423 }
424
425 /* Save the name */
426 ReparseNewDir:
427 RemainingPath = *ObjectName;
428
429 /* Reparse */
430 while (TRUE)
431 {
432 /* Check if we should use the Root Directory */
433 if (!InsideRoot)
434 {
435 /* Yes, use the root directory and remember that */
436 CurrentDirectory = RootDirectory;
437 InsideRoot = TRUE;
438 }
439
440 /* Check if the name starts with a path separator */
441 if ((RemainingPath.Length) &&
442 (RemainingPath.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
443 {
444 /* Skip the path separator */
445 RemainingPath.Buffer++;
446 RemainingPath.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
447 }
448
449 /* Find the next Part Name */
450 PartName = RemainingPath;
451 while (RemainingPath.Length)
452 {
453 /* Break if we found the \ ending */
454 if (RemainingPath.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
455
456 /* Move on */
457 RemainingPath.Buffer++;
458 RemainingPath.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
459 }
460
461 /* Get its size and make sure it's valid */
462 if (!(PartName.Length -= RemainingPath.Length))
463 {
464 Status = STATUS_OBJECT_NAME_INVALID;
465 break;
466 }
467
468 /* Do the look up */
469 Context->DirectoryLocked = TRUE;
470 Context->Directory = CurrentDirectory;
471 CurrentObject = ObpLookupEntryDirectory(CurrentDirectory,
472 &PartName,
473 Attributes,
474 FALSE,
475 Context);
476 if (!CurrentObject)
477 {
478 /* We didn't find it... do we still have a path? */
479 if (RemainingPath.Length)
480 {
481 /* Then tell the caller the path wasn't found */
482 Status = STATUS_OBJECT_PATH_NOT_FOUND;
483 break;
484 }
485 else if (!ExpectedObject)
486 {
487 /* Otherwise, we have a path, but the name isn't valid */
488 Status = STATUS_OBJECT_NAME_NOT_FOUND;
489 break;
490 }
491
492 /* Reference newly to be inserted object */
493 ObReferenceObject(ExpectedObject);
494 CurrentHeader = OBJECT_TO_OBJECT_HEADER(ExpectedObject);
495
496 /* Create Object Name */
497 NewName = ExAllocatePoolWithTag(NonPagedPool,
498 PartName.MaximumLength,
499 OB_NAME_TAG);
500 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(CurrentHeader);
501
502 /* Copy the Name */
503 RtlCopyMemory(NewName, PartName.Buffer, PartName.MaximumLength);
504
505 /* Free old name */
506 if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer);
507
508 /* Write new one */
509 ObjectNameInfo->Name.Buffer = NewName;
510 ObjectNameInfo->Name.Length = PartName.Length;
511 ObjectNameInfo->Name.MaximumLength = PartName.MaximumLength;
512
513 /* Rereference the Directory and insert */
514 ObReferenceObject(CurrentDirectory);
515 ObpInsertEntryDirectory(CurrentDirectory, Context, CurrentHeader);
516
517 /* Return Status and the Expected Object */
518 Status = STATUS_SUCCESS;
519 CurrentObject = ExpectedObject;
520
521 /* Get out of here */
522 break;
523 }
524
525 Reparse:
526 /* We found it, so now get its header */
527 CurrentHeader = OBJECT_TO_OBJECT_HEADER(CurrentObject);
528
529 /*
530 * Check for a parse Procedure, but don't bother to parse for an insert
531 * unless it's a Symbolic Link, in which case we MUST parse
532 */
533 ParseRoutine = CurrentHeader->Type->TypeInfo.ParseProcedure;
534 if (ParseRoutine &&
535 (!ExpectedObject || ParseRoutine == ObpParseSymbolicLink))
536 {
537 /* Use the Root Directory next time */
538 InsideRoot = FALSE;
539
540 /* Call the Parse Procedure */
541 Status = ParseRoutine(CurrentObject,
542 ObjectType,
543 AccessState,
544 AccessMode,
545 Attributes,
546 ObjectName,
547 &RemainingPath,
548 ParseContext,
549 SecurityQos,
550 &CurrentObject);
551
552 /* Check if we have to reparse */
553 if ((Status == STATUS_REPARSE) ||
554 (Status == STATUS_REPARSE_OBJECT))
555 {
556 /* Start over from root if we got sent back there */
557 if ((Status == STATUS_REPARSE_OBJECT) ||
558 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
559 {
560 /* Check if we got a root directory */
561 if (RootHandle)
562 {
563 /* Stop using it, because we have a new directory now */
564 ObDereferenceObject(RootDirectory);
565 RootHandle = NULL;
566 }
567
568 /* Start at Root */
569 RootDirectory = NameSpaceRoot;
570
571 /* Check for reparse status */
572 if (Status == STATUS_REPARSE_OBJECT)
573 {
574 /* Did we actually get an object to which to reparse? */
575 if (!CurrentObject)
576 {
577 /* We didn't, so set a failure status */
578 Status = STATUS_OBJECT_NAME_NOT_FOUND;
579 }
580 else
581 {
582 /* We did, so we're free to parse the new object */
583 InsideRoot = TRUE;
584 goto Reparse;
585 }
586 }
587
588 /* Restart the search */
589 goto ReparseNewDir;
590 }
591 else if (RootDirectory == NameSpaceRoot)
592 {
593 /* We got STATUS_REPARSE but are at the Root Directory */
594 CurrentObject = NULL;
595 Status = STATUS_OBJECT_NAME_NOT_FOUND;
596 }
597 }
598 else if (!NT_SUCCESS(Status))
599 {
600 /* Total failure */
601 CurrentObject = NULL;
602 }
603 else if (!CurrentObject)
604 {
605 /* We didn't reparse but we didn't find the Object Either */
606 Status = STATUS_OBJECT_NAME_NOT_FOUND;
607 }
608
609 /* Break out of the loop */
610 break;
611 }
612 else
613 {
614 /* No parse routine...do we still have a remaining name? */
615 if (!RemainingPath.Length)
616 {
617 /* Are we creating an object? */
618 if (!ExpectedObject)
619 {
620 /* We don't... reference the Object */
621 Status = ObReferenceObjectByPointer(CurrentObject,
622 0,
623 ObjectType,
624 AccessMode);
625 if (!NT_SUCCESS(Status)) CurrentObject = NULL;
626 }
627
628 /* And get out of the reparse loop */
629 break;
630 }
631 else
632 {
633 /* We still have a name; check if this is a directory object */
634 if (CurrentHeader->Type == ObDirectoryType)
635 {
636 /* Restart from this directory */
637 CurrentDirectory = CurrentObject;
638 }
639 else
640 {
641 /* We still have a name, but no parse routine for it */
642 Status = STATUS_OBJECT_TYPE_MISMATCH;
643 CurrentObject = NULL;
644 break;
645 }
646 }
647 }
648 }
649
650 /* Write what we found, and if it's null, check if we got success */
651 if (!(*ReturnedObject = CurrentObject) && (NT_SUCCESS(Status)))
652 {
653 /* Nothing found... but we have success. Correct the status code */
654 Status = STATUS_OBJECT_NAME_NOT_FOUND;
655 }
656
657 /* Check if we had a root directory */
658 if (RootHandle)
659 {
660 /* Dereference it */
661 ObDereferenceObject(RootDirectory);
662 }
663
664 /* Return status to caller */
665 OBTRACE(OB_NAMESPACE_DEBUG,
666 "%s - Found Object: %p. Expected: %p\n",
667 __FUNCTION__,
668 *ReturnedObject,
669 ExpectedObject);
670 return Status;
671 }
672
673 /* PUBLIC FUNCTIONS *********************************************************/
674
675 NTSTATUS
676 NTAPI
677 ObQueryNameString(IN PVOID Object,
678 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
679 IN ULONG Length,
680 OUT PULONG ReturnLength)
681 {
682 POBJECT_HEADER_NAME_INFO LocalInfo;
683 POBJECT_HEADER ObjectHeader;
684 POBJECT_DIRECTORY ParentDirectory;
685 ULONG NameSize;
686 PWCH ObjectName;
687
688 /* Get the Kernel Meta-Structures */
689 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
690 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
691
692 /* Check if a Query Name Procedure is available */
693 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
694 {
695 /* Call the procedure */
696 return ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
697 TRUE, //fixme
698 ObjectNameInfo,
699 Length,
700 ReturnLength,
701 KernelMode);
702 }
703
704 /* Check if the object doesn't even have a name */
705 if (!(LocalInfo) || !(LocalInfo->Name.Buffer))
706 {
707 /* We're returning the name structure */
708 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
709
710 /* Check if we were given enough space */
711 if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
712
713 /* Return an empty buffer */
714 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
715 return STATUS_SUCCESS;
716 }
717
718 /*
719 * Find the size needed for the name. We won't do
720 * this during the Name Creation loop because we want
721 * to let the caller know that the buffer isn't big
722 * enough right at the beginning, not work our way through
723 * and find out at the end
724 */
725 if (Object == NameSpaceRoot)
726 {
727 /* Size of the '\' string */
728 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
729 }
730 else
731 {
732 /* Get the Object Directory and add name of Object */
733 ParentDirectory = LocalInfo->Directory;
734 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
735
736 /* Loop inside the directory to get the top-most one (meaning root) */
737 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
738 {
739 /* Get the Name Information */
740 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
741 OBJECT_TO_OBJECT_HEADER(ParentDirectory));
742
743 /* Add the size of the Directory Name */
744 if (LocalInfo && LocalInfo->Directory)
745 {
746 /* Size of the '\' string + Directory Name */
747 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) +
748 LocalInfo->Name.Length;
749
750 /* Move to next parent Directory */
751 ParentDirectory = LocalInfo->Directory;
752 }
753 else
754 {
755 /* Directory with no name. We append "...\" */
756 NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
757 break;
758 }
759 }
760 }
761
762 /* Finally, add the name of the structure and the null char */
763 *ReturnLength = NameSize +
764 sizeof(OBJECT_NAME_INFORMATION) +
765 sizeof(UNICODE_NULL);
766
767 /* Check if we were given enough space */
768 if (*ReturnLength > Length) return STATUS_INFO_LENGTH_MISMATCH;
769
770 /*
771 * Now we will actually create the name. We work backwards because
772 * it's easier to start off from the Name we have and walk up the
773 * parent directories. We use the same logic as Name Length calculation.
774 */
775 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
776 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
777 *--ObjectName = UNICODE_NULL;
778
779 /* Check if the object is actually the Root directory */
780 if (Object == NameSpaceRoot)
781 {
782 /* This is already the Root Directory, return "\\" */
783 *--ObjectName = OBJ_NAME_PATH_SEPARATOR;
784 ObjectNameInfo->Name.Length = (USHORT)NameSize;
785 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
786 sizeof(UNICODE_NULL));
787 ObjectNameInfo->Name.Buffer = ObjectName;
788 return STATUS_SUCCESS;
789 }
790 else
791 {
792 /* Start by adding the Object's Name */
793 ObjectName = (PWCH)((ULONG_PTR)ObjectName -
794 LocalInfo->Name.Length);
795 RtlCopyMemory(ObjectName,
796 LocalInfo->Name.Buffer,
797 LocalInfo->Name.Length);
798
799 /* Now parse the Parent directories until we reach the top */
800 ParentDirectory = LocalInfo->Directory;
801 while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
802 {
803 /* Get the name information */
804 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
805 OBJECT_TO_OBJECT_HEADER(ParentDirectory));
806
807 /* Add the "\" */
808 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
809
810 /* Add the Parent Directory's Name */
811 if (LocalInfo && LocalInfo->Name.Buffer)
812 {
813 /* Add the name */
814 ObjectName = (PWCH)((ULONG_PTR)ObjectName -
815 LocalInfo->Name.Length);
816 RtlCopyMemory(ObjectName,
817 LocalInfo->Name.Buffer,
818 LocalInfo->Name.Length);
819
820 /* Move to next parent */
821 ParentDirectory = LocalInfo->Directory;
822 }
823 else
824 {
825 /* Directory without a name, we add "..." */
826 DPRINT("Nameless Directory\n");
827 ObjectName -= sizeof(L"...");
828 ObjectName = L"...";
829 break;
830 }
831 }
832
833 /* Add Root Directory Name */
834 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
835 ObjectNameInfo->Name.Length = (USHORT)NameSize;
836 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
837 sizeof(UNICODE_NULL));
838 ObjectNameInfo->Name.Buffer = ObjectName;
839 }
840
841 /* Return success */
842 return STATUS_SUCCESS;
843 }
844
845 VOID
846 NTAPI
847 ObQueryDeviceMapInformation(IN PEPROCESS Process,
848 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo)
849 {
850 //KIRQL OldIrql ;
851
852 /*
853 * FIXME: This is an ugly hack for now, to always return the System Device Map
854 * instead of returning the Process Device Map. Not important yet since we don't use it
855 */
856
857 /* FIXME: Acquire the DeviceMap Spinlock */
858 // KeAcquireSpinLock(DeviceMap->Lock, &OldIrql);
859
860 /* Make a copy */
861 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap;
862 RtlCopyMemory(DeviceMapInfo->Query.DriveType,
863 ObSystemDeviceMap->DriveType,
864 sizeof(ObSystemDeviceMap->DriveType));
865
866 /* FIXME: Release the DeviceMap Spinlock */
867 // KeReleasepinLock(DeviceMap->Lock, OldIrql);
868 }
869
870 /* EOF */