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