Merge 14981:15268 from trunk
[reactos.git] / reactos / ntoskrnl / cm / regobj.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/regobj.c
6 * PURPOSE: Registry object manipulation routines.
7 *
8 * PROGRAMMERS: No programmer listed.
9 */
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 #include "cm.h"
16
17 extern LIST_ENTRY CmiKeyObjectListHead;
18 extern ULONG CmiTimer;
19
20 static NTSTATUS
21 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
22 PKEY_CELL KeyCell,
23 PUNICODE_STRING TargetPath);
24
25 /* FUNCTONS *****************************************************************/
26
27 NTSTATUS STDCALL
28 CmiObjectParse(PVOID ParsedObject,
29 PVOID *NextObject,
30 PUNICODE_STRING FullPath,
31 PWSTR *Path,
32 ULONG Attributes)
33 {
34 BLOCK_OFFSET BlockOffset;
35 PKEY_OBJECT FoundObject;
36 PKEY_OBJECT ParsedKey;
37 PKEY_CELL SubKeyCell;
38 NTSTATUS Status;
39 PWSTR StartPtr;
40 PWSTR EndPtr;
41 ULONG Length;
42 UNICODE_STRING LinkPath;
43 UNICODE_STRING TargetPath;
44 UNICODE_STRING KeyName;
45
46 ParsedKey = ParsedObject;
47
48 VERIFY_KEY_OBJECT(ParsedKey);
49
50 *NextObject = NULL;
51
52 if ((*Path) == NULL)
53 {
54 DPRINT("*Path is NULL\n");
55 return STATUS_UNSUCCESSFUL;
56 }
57
58 DPRINT("Path '%S'\n", *Path);
59
60 /* Extract relevant path name */
61 StartPtr = *Path;
62 if (*StartPtr == L'\\')
63 StartPtr++;
64
65 EndPtr = wcschr(StartPtr, L'\\');
66 if (EndPtr != NULL)
67 Length = ((PCHAR)EndPtr - (PCHAR)StartPtr) / sizeof(WCHAR);
68 else
69 Length = wcslen(StartPtr);
70
71
72 KeyName.Length = Length * sizeof(WCHAR);
73 KeyName.MaximumLength = KeyName.Length + sizeof(WCHAR);
74 KeyName.Buffer = ExAllocatePool(NonPagedPool,
75 KeyName.MaximumLength);
76 RtlCopyMemory(KeyName.Buffer,
77 StartPtr,
78 KeyName.Length);
79 KeyName.Buffer[KeyName.Length / sizeof(WCHAR)] = 0;
80
81 /* Acquire hive lock */
82 KeEnterCriticalRegion();
83 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
84
85
86 Status = CmiScanKeyList(ParsedKey,
87 &KeyName,
88 Attributes,
89 &FoundObject);
90 if (!NT_SUCCESS(Status))
91 {
92 ExReleaseResourceLite(&CmiRegistryLock);
93 KeLeaveCriticalRegion();
94 RtlFreeUnicodeString(&KeyName);
95 return Status;
96 }
97 if (FoundObject == NULL)
98 {
99 Status = CmiScanForSubKey(ParsedKey->RegistryHive,
100 ParsedKey->KeyCell,
101 &SubKeyCell,
102 &BlockOffset,
103 &KeyName,
104 0,
105 Attributes);
106 if (!NT_SUCCESS(Status) || (SubKeyCell == NULL))
107 {
108 ExReleaseResourceLite(&CmiRegistryLock);
109 KeLeaveCriticalRegion();
110 RtlFreeUnicodeString(&KeyName);
111 return(STATUS_UNSUCCESSFUL);
112 }
113
114 if ((SubKeyCell->Flags & REG_KEY_LINK_CELL) &&
115 !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL)))
116 {
117 RtlInitUnicodeString(&LinkPath, NULL);
118 Status = CmiGetLinkTarget(ParsedKey->RegistryHive,
119 SubKeyCell,
120 &LinkPath);
121 if (NT_SUCCESS(Status))
122 {
123 ExReleaseResourceLite(&CmiRegistryLock);
124 KeLeaveCriticalRegion();
125
126 DPRINT("LinkPath '%wZ'\n", &LinkPath);
127
128 /* build new FullPath for reparsing */
129 TargetPath.MaximumLength = LinkPath.MaximumLength;
130 if (EndPtr != NULL)
131 {
132 TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR));
133 }
134 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
135 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
136 TargetPath.MaximumLength);
137 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
138 if (EndPtr != NULL)
139 {
140 wcscat(TargetPath.Buffer, EndPtr);
141 }
142
143 RtlFreeUnicodeString(FullPath);
144 RtlFreeUnicodeString(&LinkPath);
145 FullPath->Length = TargetPath.Length;
146 FullPath->MaximumLength = TargetPath.MaximumLength;
147 FullPath->Buffer = TargetPath.Buffer;
148
149 DPRINT("FullPath '%wZ'\n", FullPath);
150
151 /* reinitialize Path for reparsing */
152 *Path = FullPath->Buffer;
153
154 *NextObject = NULL;
155
156 RtlFreeUnicodeString(&KeyName);
157 return(STATUS_REPARSE);
158 }
159 }
160
161 /* Create new key object and put into linked list */
162 DPRINT("CmiObjectParse: %S\n", *Path);
163 Status = ObCreateObject(KernelMode,
164 CmiKeyType,
165 NULL,
166 KernelMode,
167 NULL,
168 sizeof(KEY_OBJECT),
169 0,
170 0,
171 (PVOID*)&FoundObject);
172 if (!NT_SUCCESS(Status))
173 {
174 ExReleaseResourceLite(&CmiRegistryLock);
175 KeLeaveCriticalRegion();
176 RtlFreeUnicodeString(&KeyName);
177 return(Status);
178 }
179 /* Add the keep-alive reference */
180 ObReferenceObject(FoundObject);
181
182 FoundObject->Flags = 0;
183 FoundObject->KeyCell = SubKeyCell;
184 FoundObject->KeyCellOffset = BlockOffset;
185 FoundObject->RegistryHive = ParsedKey->RegistryHive;
186 InsertTailList(&CmiKeyObjectListHead, &FoundObject->ListEntry);
187 RtlpCreateUnicodeString(&FoundObject->Name,
188 KeyName.Buffer, NonPagedPool);
189 CmiAddKeyToList(ParsedKey, FoundObject);
190 DPRINT("Created object 0x%x\n", FoundObject);
191 }
192 else
193 {
194 if ((FoundObject->KeyCell->Flags & REG_KEY_LINK_CELL) &&
195 !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL)))
196 {
197 DPRINT("Found link\n");
198
199 RtlInitUnicodeString(&LinkPath, NULL);
200 Status = CmiGetLinkTarget(FoundObject->RegistryHive,
201 FoundObject->KeyCell,
202 &LinkPath);
203 if (NT_SUCCESS(Status))
204 {
205 DPRINT("LinkPath '%wZ'\n", &LinkPath);
206
207 ExReleaseResourceLite(&CmiRegistryLock);
208 KeLeaveCriticalRegion();
209
210 ObDereferenceObject(FoundObject);
211
212 /* build new FullPath for reparsing */
213 TargetPath.MaximumLength = LinkPath.MaximumLength;
214 if (EndPtr != NULL)
215 {
216 TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR));
217 }
218 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
219 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
220 TargetPath.MaximumLength);
221 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
222 if (EndPtr != NULL)
223 {
224 wcscat(TargetPath.Buffer, EndPtr);
225 }
226
227 RtlFreeUnicodeString(FullPath);
228 RtlFreeUnicodeString(&LinkPath);
229 FullPath->Length = TargetPath.Length;
230 FullPath->MaximumLength = TargetPath.MaximumLength;
231 FullPath->Buffer = TargetPath.Buffer;
232
233 DPRINT("FullPath '%wZ'\n", FullPath);
234
235 /* reinitialize Path for reparsing */
236 *Path = FullPath->Buffer;
237
238 *NextObject = NULL;
239
240 RtlFreeUnicodeString(&KeyName);
241 return(STATUS_REPARSE);
242 }
243 }
244 }
245
246 RemoveEntryList(&FoundObject->ListEntry);
247 InsertHeadList(&CmiKeyObjectListHead, &FoundObject->ListEntry);
248 FoundObject->TimeStamp = CmiTimer;
249
250 ExReleaseResourceLite(&CmiRegistryLock);
251 KeLeaveCriticalRegion();
252
253 DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
254
255 *Path = EndPtr;
256
257 VERIFY_KEY_OBJECT(FoundObject);
258
259 *NextObject = FoundObject;
260
261 RtlFreeUnicodeString(&KeyName);
262
263 return(STATUS_SUCCESS);
264 }
265
266
267 NTSTATUS STDCALL
268 CmiObjectCreate(PVOID ObjectBody,
269 PVOID Parent,
270 PWSTR RemainingPath,
271 POBJECT_ATTRIBUTES ObjectAttributes)
272 {
273 PKEY_OBJECT KeyObject = ObjectBody;
274 PWSTR Start;
275
276 KeyObject->ParentKey = Parent;
277 if (RemainingPath)
278 {
279 Start = RemainingPath;
280 if(*Start == L'\\')
281 Start++;
282 RtlpCreateUnicodeString(&KeyObject->Name,
283 Start, NonPagedPool);
284 }
285 else
286 {
287 RtlInitUnicodeString(&KeyObject->Name,
288 NULL);
289 }
290
291 return STATUS_SUCCESS;
292 }
293
294
295 VOID STDCALL
296 CmiObjectDelete(PVOID DeletedObject)
297 {
298 PKEY_OBJECT ParentKeyObject;
299 PKEY_OBJECT KeyObject;
300
301 DPRINT("Delete key object (%p)\n", DeletedObject);
302
303 KeyObject = (PKEY_OBJECT) DeletedObject;
304 ParentKeyObject = KeyObject->ParentKey;
305
306 ObReferenceObject (ParentKeyObject);
307
308 /* Acquire hive lock */
309 KeEnterCriticalRegion();
310 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
311
312 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
313 {
314 DPRINT1("Key not found in parent list ???\n");
315 }
316
317 RemoveEntryList(&KeyObject->ListEntry);
318 RtlFreeUnicodeString(&KeyObject->Name);
319
320 if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
321 {
322 DPRINT("delete really key\n");
323
324 CmiRemoveSubKey(KeyObject->RegistryHive,
325 ParentKeyObject,
326 KeyObject);
327
328 KeQuerySystemTime (&ParentKeyObject->KeyCell->LastWriteTime);
329 CmiMarkBlockDirty (ParentKeyObject->RegistryHive,
330 ParentKeyObject->KeyCellOffset);
331
332 if (!IsNoFileHive (KeyObject->RegistryHive) ||
333 !IsNoFileHive (ParentKeyObject->RegistryHive))
334 {
335 CmiSyncHives ();
336 }
337 }
338
339 ObDereferenceObject (ParentKeyObject);
340
341 ExReleaseResourceLite(&CmiRegistryLock);
342 KeLeaveCriticalRegion();
343
344 if (KeyObject->NumberOfSubKeys)
345 {
346 KEBUGCHECK(REGISTRY_ERROR);
347 }
348
349 if (KeyObject->SizeOfSubKeys)
350 {
351 ExFreePool(KeyObject->SubKeys);
352 }
353 }
354
355
356 static NTSTATUS
357 CmiQuerySecurityDescriptor(PKEY_OBJECT KeyObject,
358 SECURITY_INFORMATION SecurityInformation,
359 PSECURITY_DESCRIPTOR SecurityDescriptor,
360 PULONG BufferLength)
361 {
362 ULONG_PTR Current;
363 ULONG SidSize;
364 ULONG SdSize;
365 NTSTATUS Status;
366
367 DPRINT("CmiQuerySecurityDescriptor() called\n");
368
369 /*
370 * FIXME:
371 * This is a big hack!!
372 * We need to retrieve the security descriptor from the keys security cell!
373 */
374
375 if (SecurityInformation == 0)
376 {
377 return STATUS_ACCESS_DENIED;
378 }
379
380 SidSize = RtlLengthSid(SeWorldSid);
381 SdSize = sizeof(SECURITY_DESCRIPTOR) + (2 * SidSize);
382
383 if (*BufferLength < SdSize)
384 {
385 *BufferLength = SdSize;
386 return STATUS_BUFFER_TOO_SMALL;
387 }
388
389 *BufferLength = SdSize;
390
391 Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
392 SECURITY_DESCRIPTOR_REVISION);
393 if (!NT_SUCCESS(Status))
394 {
395 return Status;
396 }
397
398 SecurityDescriptor->Control |= SE_SELF_RELATIVE;
399 Current = (ULONG_PTR)SecurityDescriptor + sizeof(SECURITY_DESCRIPTOR);
400
401 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
402 {
403 RtlCopyMemory((PVOID)Current,
404 SeWorldSid,
405 SidSize);
406 SecurityDescriptor->Owner = (PSID)((ULONG_PTR)Current - (ULONG_PTR)SecurityDescriptor);
407 Current += SidSize;
408 }
409
410 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
411 {
412 RtlCopyMemory((PVOID)Current,
413 SeWorldSid,
414 SidSize);
415 SecurityDescriptor->Group = (PSID)((ULONG_PTR)Current - (ULONG_PTR)SecurityDescriptor);
416 Current += SidSize;
417 }
418
419 if (SecurityInformation & DACL_SECURITY_INFORMATION)
420 {
421 SecurityDescriptor->Control |= SE_DACL_PRESENT;
422 }
423
424 if (SecurityInformation & SACL_SECURITY_INFORMATION)
425 {
426 SecurityDescriptor->Control |= SE_SACL_PRESENT;
427 }
428
429 return STATUS_SUCCESS;
430 }
431
432
433 static NTSTATUS
434 CmiAssignSecurityDescriptor(PKEY_OBJECT KeyObject,
435 PSECURITY_DESCRIPTOR SecurityDescriptor)
436 {
437 #if 0
438 PREGISTRY_HIVE Hive;
439
440 DPRINT1("CmiAssignSecurityDescriptor() callled\n");
441
442 DPRINT1("KeyObject %p\n", KeyObject);
443 DPRINT1("KeyObject->RegistryHive %p\n", KeyObject->RegistryHive);
444
445 Hive = KeyObject->RegistryHive;
446 if (Hive == NULL)
447 {
448 DPRINT1("Create new root security cell\n");
449 return STATUS_SUCCESS;
450 }
451
452 if (Hive->RootSecurityCell == NULL)
453 {
454 DPRINT1("Create new root security cell\n");
455
456 }
457 else
458 {
459 DPRINT1("Search for security cell\n");
460
461 }
462 #endif
463
464 return STATUS_SUCCESS;
465 }
466
467
468 NTSTATUS STDCALL
469 CmiObjectSecurity(PVOID ObjectBody,
470 SECURITY_OPERATION_CODE OperationCode,
471 SECURITY_INFORMATION SecurityInformation,
472 PSECURITY_DESCRIPTOR SecurityDescriptor,
473 PULONG BufferLength)
474 {
475 DPRINT("CmiObjectSecurity() called\n");
476
477 switch (OperationCode)
478 {
479 case SetSecurityDescriptor:
480 DPRINT("Set security descriptor\n");
481 return STATUS_SUCCESS;
482
483 case QuerySecurityDescriptor:
484 DPRINT("Query security descriptor\n");
485 return CmiQuerySecurityDescriptor((PKEY_OBJECT)ObjectBody,
486 SecurityInformation,
487 SecurityDescriptor,
488 BufferLength);
489
490 case DeleteSecurityDescriptor:
491 DPRINT("Delete security descriptor\n");
492 return STATUS_SUCCESS;
493
494 case AssignSecurityDescriptor:
495 DPRINT("Assign security descriptor\n");
496 return CmiAssignSecurityDescriptor((PKEY_OBJECT)ObjectBody,
497 SecurityDescriptor);
498 }
499
500 return STATUS_UNSUCCESSFUL;
501 }
502
503
504 NTSTATUS STDCALL
505 CmiObjectQueryName (PVOID ObjectBody,
506 POBJECT_NAME_INFORMATION ObjectNameInfo,
507 ULONG Length,
508 PULONG ReturnLength)
509 {
510 POBJECT_NAME_INFORMATION LocalInfo;
511 PKEY_OBJECT KeyObject;
512 ULONG LocalReturnLength;
513 NTSTATUS Status;
514
515 DPRINT ("CmiObjectQueryName() called\n");
516
517 KeyObject = (PKEY_OBJECT)ObjectBody;
518
519 LocalInfo = ExAllocatePool (NonPagedPool,
520 sizeof(OBJECT_NAME_INFORMATION) +
521 MAX_PATH * sizeof(WCHAR));
522 if (LocalInfo == NULL)
523 return STATUS_INSUFFICIENT_RESOURCES;
524
525 if (KeyObject->ParentKey != KeyObject)
526 {
527 Status = ObQueryNameString (KeyObject->ParentKey,
528 LocalInfo,
529 MAX_PATH * sizeof(WCHAR),
530 &LocalReturnLength);
531 }
532 else
533 {
534 /* KeyObject is the root key */
535 Status = ObQueryNameString (BODY_TO_HEADER(KeyObject)->Parent,
536 LocalInfo,
537 MAX_PATH * sizeof(WCHAR),
538 &LocalReturnLength);
539 }
540
541 if (!NT_SUCCESS (Status))
542 {
543 ExFreePool (LocalInfo);
544 return Status;
545 }
546 DPRINT ("Parent path: %wZ\n", &LocalInfo->Name);
547
548 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
549 &LocalInfo->Name);
550 ExFreePool (LocalInfo);
551 if (!NT_SUCCESS (Status))
552 return Status;
553
554 Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
555 L"\\");
556 if (!NT_SUCCESS (Status))
557 return Status;
558
559 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
560 &KeyObject->Name);
561 if (NT_SUCCESS (Status))
562 {
563 DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name);
564 }
565
566 return Status;
567 }
568
569
570 VOID
571 CmiAddKeyToList(PKEY_OBJECT ParentKey,
572 PKEY_OBJECT NewKey)
573 {
574
575 DPRINT("ParentKey %.08x\n", ParentKey);
576
577
578 if (ParentKey->SizeOfSubKeys <= ParentKey->NumberOfSubKeys)
579 {
580 PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
581 (ParentKey->NumberOfSubKeys + 1) * sizeof(ULONG));
582
583 if (ParentKey->NumberOfSubKeys > 0)
584 {
585 RtlCopyMemory (tmpSubKeys,
586 ParentKey->SubKeys,
587 ParentKey->NumberOfSubKeys * sizeof(ULONG));
588 }
589
590 if (ParentKey->SubKeys)
591 ExFreePool(ParentKey->SubKeys);
592
593 ParentKey->SubKeys = tmpSubKeys;
594 ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
595 }
596
597 /* FIXME: Please maintain the list in alphabetic order */
598 /* to allow a dichotomic search */
599 ParentKey->SubKeys[ParentKey->NumberOfSubKeys++] = NewKey;
600
601 DPRINT("Reference parent key: 0x%x\n", ParentKey);
602
603 ObReferenceObjectByPointer(ParentKey,
604 STANDARD_RIGHTS_REQUIRED,
605 NULL,
606 UserMode);
607 NewKey->ParentKey = ParentKey;
608 }
609
610
611 NTSTATUS
612 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
613 {
614 PKEY_OBJECT ParentKey;
615 DWORD Index;
616
617 ParentKey = KeyToRemove->ParentKey;
618 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
619 for (Index = 0; Index < ParentKey->NumberOfSubKeys; Index++)
620 {
621 if (ParentKey->SubKeys[Index] == KeyToRemove)
622 {
623 if (Index < ParentKey->NumberOfSubKeys-1)
624 RtlMoveMemory(&ParentKey->SubKeys[Index],
625 &ParentKey->SubKeys[Index + 1],
626 (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
627 ParentKey->NumberOfSubKeys--;
628
629 DPRINT("Dereference parent key: 0x%x\n", ParentKey);
630
631 ObDereferenceObject(ParentKey);
632 return STATUS_SUCCESS;
633 }
634 }
635
636 return STATUS_UNSUCCESSFUL;
637 }
638
639
640 NTSTATUS
641 CmiScanKeyList(PKEY_OBJECT Parent,
642 PUNICODE_STRING KeyName,
643 ULONG Attributes,
644 PKEY_OBJECT* ReturnedObject)
645 {
646 PKEY_OBJECT CurKey;
647 ULONG Index;
648
649 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
650 KeyName, &Parent->Name);
651
652 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
653 for (Index=0; Index < Parent->NumberOfSubKeys; Index++)
654 {
655 CurKey = Parent->SubKeys[Index];
656 if (Attributes & OBJ_CASE_INSENSITIVE)
657 {
658 if ((KeyName->Length == CurKey->Name.Length)
659 && (_wcsicmp(KeyName->Buffer, CurKey->Name.Buffer) == 0))
660 {
661 break;
662 }
663 }
664 else
665 {
666 if ((KeyName->Length == CurKey->Name.Length)
667 && (wcscmp(KeyName->Buffer, CurKey->Name.Buffer) == 0))
668 {
669 break;
670 }
671 }
672 }
673
674 if (Index < Parent->NumberOfSubKeys)
675 {
676 if (CurKey->Flags & KO_MARKED_FOR_DELETE)
677 {
678 *ReturnedObject = NULL;
679 return STATUS_UNSUCCESSFUL;
680 }
681 ObReferenceObject(CurKey);
682 *ReturnedObject = CurKey;
683 }
684 else
685 {
686 *ReturnedObject = NULL;
687 }
688 return STATUS_SUCCESS;
689 }
690
691
692 static NTSTATUS
693 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
694 PKEY_CELL KeyCell,
695 PUNICODE_STRING TargetPath)
696 {
697 UNICODE_STRING LinkName = ROS_STRING_INITIALIZER(L"SymbolicLinkValue");
698 PVALUE_CELL ValueCell;
699 PDATA_CELL DataCell;
700 NTSTATUS Status;
701
702 DPRINT("CmiGetLinkTarget() called\n");
703
704 /* Get Value block of interest */
705 Status = CmiScanKeyForValue(RegistryHive,
706 KeyCell,
707 &LinkName,
708 &ValueCell,
709 NULL);
710 if (!NT_SUCCESS(Status))
711 {
712 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status);
713 return(Status);
714 }
715
716 if (ValueCell->DataType != REG_LINK)
717 {
718 DPRINT1("Type != REG_LINK\n!");
719 return(STATUS_UNSUCCESSFUL);
720 }
721
722 if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0)
723 {
724 TargetPath->Length = 0;
725 TargetPath->MaximumLength = ValueCell->DataSize + sizeof(WCHAR);
726 TargetPath->Buffer = ExAllocatePool(NonPagedPool,
727 TargetPath->MaximumLength);
728 }
729
730 TargetPath->Length = min(TargetPath->MaximumLength - sizeof(WCHAR),
731 (ULONG) ValueCell->DataSize);
732
733 if (ValueCell->DataSize > 0)
734 {
735 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
736 RtlCopyMemory(TargetPath->Buffer,
737 DataCell->Data,
738 TargetPath->Length);
739 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
740 }
741 else
742 {
743 RtlCopyMemory(TargetPath->Buffer,
744 &ValueCell->DataOffset,
745 TargetPath->Length);
746 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
747 }
748
749 DPRINT("TargetPath '%wZ'\n", TargetPath);
750
751 return(STATUS_SUCCESS);
752 }
753
754 /* EOF */