Move some profile stuff to NDK and fix some bugs in the executive implementation...
[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 DPRINT("Inserting Key into Object Tree\n");
180 Status = ObInsertObject((PVOID)FoundObject,
181 NULL,
182 KEY_ALL_ACCESS,
183 0,
184 NULL,
185 NULL);
186 DPRINT("Status %x\n", Status);
187
188 /* Add the keep-alive reference */
189 ObReferenceObject(FoundObject);
190
191 FoundObject->Flags = 0;
192 FoundObject->KeyCell = SubKeyCell;
193 FoundObject->KeyCellOffset = BlockOffset;
194 FoundObject->RegistryHive = ParsedKey->RegistryHive;
195 InsertTailList(&CmiKeyObjectListHead, &FoundObject->ListEntry);
196 RtlpCreateUnicodeString(&FoundObject->Name,
197 KeyName.Buffer, NonPagedPool);
198 CmiAddKeyToList(ParsedKey, FoundObject);
199 DPRINT("Created object 0x%p\n", FoundObject);
200 }
201 else
202 {
203 if ((FoundObject->KeyCell->Flags & REG_KEY_LINK_CELL) &&
204 !((Attributes & OBJ_OPENLINK) && (EndPtr == NULL)))
205 {
206 DPRINT("Found link\n");
207
208 RtlInitUnicodeString(&LinkPath, NULL);
209 Status = CmiGetLinkTarget(FoundObject->RegistryHive,
210 FoundObject->KeyCell,
211 &LinkPath);
212 if (NT_SUCCESS(Status))
213 {
214 DPRINT("LinkPath '%wZ'\n", &LinkPath);
215
216 ExReleaseResourceLite(&CmiRegistryLock);
217 KeLeaveCriticalRegion();
218
219 ObDereferenceObject(FoundObject);
220
221 /* build new FullPath for reparsing */
222 TargetPath.MaximumLength = LinkPath.MaximumLength;
223 if (EndPtr != NULL)
224 {
225 TargetPath.MaximumLength += (wcslen(EndPtr) * sizeof(WCHAR));
226 }
227 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
228 TargetPath.Buffer = ExAllocatePool(NonPagedPool,
229 TargetPath.MaximumLength);
230 wcscpy(TargetPath.Buffer, LinkPath.Buffer);
231 if (EndPtr != NULL)
232 {
233 wcscat(TargetPath.Buffer, EndPtr);
234 }
235
236 RtlFreeUnicodeString(FullPath);
237 RtlFreeUnicodeString(&LinkPath);
238 FullPath->Length = TargetPath.Length;
239 FullPath->MaximumLength = TargetPath.MaximumLength;
240 FullPath->Buffer = TargetPath.Buffer;
241
242 DPRINT("FullPath '%wZ'\n", FullPath);
243
244 /* reinitialize Path for reparsing */
245 *Path = FullPath->Buffer;
246
247 *NextObject = NULL;
248
249 RtlFreeUnicodeString(&KeyName);
250 return(STATUS_REPARSE);
251 }
252 }
253 }
254
255 RemoveEntryList(&FoundObject->ListEntry);
256 InsertHeadList(&CmiKeyObjectListHead, &FoundObject->ListEntry);
257 FoundObject->TimeStamp = CmiTimer;
258
259 ExReleaseResourceLite(&CmiRegistryLock);
260 KeLeaveCriticalRegion();
261
262 DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
263
264 *Path = EndPtr;
265
266 VERIFY_KEY_OBJECT(FoundObject);
267
268 *NextObject = FoundObject;
269
270 RtlFreeUnicodeString(&KeyName);
271
272 return(STATUS_SUCCESS);
273 }
274
275 VOID STDCALL
276 CmiObjectDelete(PVOID DeletedObject)
277 {
278 PKEY_OBJECT ParentKeyObject;
279 PKEY_OBJECT KeyObject;
280
281 DPRINT("Delete key object (%p)\n", DeletedObject);
282
283 KeyObject = (PKEY_OBJECT) DeletedObject;
284 ParentKeyObject = KeyObject->ParentKey;
285
286 ObReferenceObject (ParentKeyObject);
287
288 /* Acquire hive lock */
289 KeEnterCriticalRegion();
290 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
291
292 if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
293 {
294 DPRINT1("Key not found in parent list ???\n");
295 }
296
297 RemoveEntryList(&KeyObject->ListEntry);
298 RtlFreeUnicodeString(&KeyObject->Name);
299
300 if (KeyObject->Flags & KO_MARKED_FOR_DELETE)
301 {
302 DPRINT("delete really key\n");
303
304 CmiRemoveSubKey(KeyObject->RegistryHive,
305 ParentKeyObject,
306 KeyObject);
307
308 KeQuerySystemTime (&ParentKeyObject->KeyCell->LastWriteTime);
309 CmiMarkBlockDirty (ParentKeyObject->RegistryHive,
310 ParentKeyObject->KeyCellOffset);
311
312 if (!IsNoFileHive (KeyObject->RegistryHive) ||
313 !IsNoFileHive (ParentKeyObject->RegistryHive))
314 {
315 CmiSyncHives ();
316 }
317 }
318
319 ObDereferenceObject (ParentKeyObject);
320
321 ExReleaseResourceLite(&CmiRegistryLock);
322 KeLeaveCriticalRegion();
323
324 if (KeyObject->NumberOfSubKeys)
325 {
326 KEBUGCHECK(REGISTRY_ERROR);
327 }
328
329 if (KeyObject->SizeOfSubKeys)
330 {
331 ExFreePool(KeyObject->SubKeys);
332 }
333 }
334
335
336 static NTSTATUS
337 CmiQuerySecurityDescriptor(PKEY_OBJECT KeyObject,
338 SECURITY_INFORMATION SecurityInformation,
339 PISECURITY_DESCRIPTOR SecurityDescriptor,
340 PULONG BufferLength)
341 {
342 ULONG_PTR Current;
343 ULONG SidSize;
344 ULONG SdSize;
345 NTSTATUS Status;
346
347 DPRINT("CmiQuerySecurityDescriptor() called\n");
348
349 /*
350 * FIXME:
351 * This is a big hack!!
352 * We need to retrieve the security descriptor from the keys security cell!
353 */
354
355 if (SecurityInformation == 0)
356 {
357 return STATUS_ACCESS_DENIED;
358 }
359
360 SidSize = RtlLengthSid(SeWorldSid);
361 SdSize = sizeof(SECURITY_DESCRIPTOR) + (2 * SidSize);
362
363 if (*BufferLength < SdSize)
364 {
365 *BufferLength = SdSize;
366 return STATUS_BUFFER_TOO_SMALL;
367 }
368
369 *BufferLength = SdSize;
370
371 Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
372 SECURITY_DESCRIPTOR_REVISION);
373 if (!NT_SUCCESS(Status))
374 {
375 return Status;
376 }
377
378 SecurityDescriptor->Control |= SE_SELF_RELATIVE;
379 Current = (ULONG_PTR)SecurityDescriptor + sizeof(SECURITY_DESCRIPTOR);
380
381 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
382 {
383 RtlCopyMemory((PVOID)Current,
384 SeWorldSid,
385 SidSize);
386 SecurityDescriptor->Owner = (PSID)((ULONG_PTR)Current - (ULONG_PTR)SecurityDescriptor);
387 Current += SidSize;
388 }
389
390 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
391 {
392 RtlCopyMemory((PVOID)Current,
393 SeWorldSid,
394 SidSize);
395 SecurityDescriptor->Group = (PSID)((ULONG_PTR)Current - (ULONG_PTR)SecurityDescriptor);
396 Current += SidSize;
397 }
398
399 if (SecurityInformation & DACL_SECURITY_INFORMATION)
400 {
401 SecurityDescriptor->Control |= SE_DACL_PRESENT;
402 }
403
404 if (SecurityInformation & SACL_SECURITY_INFORMATION)
405 {
406 SecurityDescriptor->Control |= SE_SACL_PRESENT;
407 }
408
409 return STATUS_SUCCESS;
410 }
411
412
413 static NTSTATUS
414 CmiAssignSecurityDescriptor(PKEY_OBJECT KeyObject,
415 PSECURITY_DESCRIPTOR SecurityDescriptor)
416 {
417 #if 0
418 PREGISTRY_HIVE Hive;
419
420 DPRINT1("CmiAssignSecurityDescriptor() callled\n");
421
422 DPRINT1("KeyObject %p\n", KeyObject);
423 DPRINT1("KeyObject->RegistryHive %p\n", KeyObject->RegistryHive);
424
425 Hive = KeyObject->RegistryHive;
426 if (Hive == NULL)
427 {
428 DPRINT1("Create new root security cell\n");
429 return STATUS_SUCCESS;
430 }
431
432 if (Hive->RootSecurityCell == NULL)
433 {
434 DPRINT1("Create new root security cell\n");
435
436 }
437 else
438 {
439 DPRINT1("Search for security cell\n");
440
441 }
442 #endif
443
444 return STATUS_SUCCESS;
445 }
446
447
448 NTSTATUS STDCALL
449 CmiObjectSecurity(PVOID ObjectBody,
450 SECURITY_OPERATION_CODE OperationCode,
451 SECURITY_INFORMATION SecurityInformation,
452 PSECURITY_DESCRIPTOR SecurityDescriptor,
453 PULONG BufferLength,
454 PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
455 POOL_TYPE PoolType,
456 PGENERIC_MAPPING GenericMapping)
457 {
458 DPRINT("CmiObjectSecurity() called\n");
459
460 switch (OperationCode)
461 {
462 case SetSecurityDescriptor:
463 DPRINT("Set security descriptor\n");
464 return STATUS_SUCCESS;
465
466 case QuerySecurityDescriptor:
467 DPRINT("Query security descriptor\n");
468 return CmiQuerySecurityDescriptor((PKEY_OBJECT)ObjectBody,
469 SecurityInformation,
470 SecurityDescriptor,
471 BufferLength);
472
473 case DeleteSecurityDescriptor:
474 DPRINT("Delete security descriptor\n");
475 return STATUS_SUCCESS;
476
477 case AssignSecurityDescriptor:
478 DPRINT("Assign security descriptor\n");
479 return CmiAssignSecurityDescriptor((PKEY_OBJECT)ObjectBody,
480 SecurityDescriptor);
481 }
482
483 return STATUS_UNSUCCESSFUL;
484 }
485
486
487 NTSTATUS STDCALL
488 CmiObjectQueryName (PVOID ObjectBody,
489 POBJECT_NAME_INFORMATION ObjectNameInfo,
490 ULONG Length,
491 PULONG ReturnLength)
492 {
493 PKEY_OBJECT KeyObject;
494 NTSTATUS Status;
495
496 DPRINT ("CmiObjectQueryName() called\n");
497
498 KeyObject = (PKEY_OBJECT)ObjectBody;
499
500 if (KeyObject->ParentKey != KeyObject)
501 {
502 Status = ObQueryNameString (KeyObject->ParentKey,
503 ObjectNameInfo,
504 Length,
505 ReturnLength);
506 }
507 else
508 {
509 /* KeyObject is the root key */
510 Status = ObQueryNameString (HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(KeyObject))->Directory,
511 ObjectNameInfo,
512 Length,
513 ReturnLength);
514 }
515
516 if (!NT_SUCCESS(Status) && Status != STATUS_INFO_LENGTH_MISMATCH)
517 {
518 return Status;
519 }
520 (*ReturnLength) += sizeof(WCHAR) + KeyObject->Name.Length;
521
522 if (Status == STATUS_INFO_LENGTH_MISMATCH || *ReturnLength > Length)
523 {
524 return STATUS_INFO_LENGTH_MISMATCH;
525 }
526
527 if (ObjectNameInfo->Name.Buffer == NULL)
528 {
529 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1);
530 ObjectNameInfo->Name.Length = 0;
531 ObjectNameInfo->Name.MaximumLength = Length - sizeof(OBJECT_NAME_INFORMATION);
532 }
533
534
535 DPRINT ("Parent path: %wZ\n", ObjectNameInfo->Name);
536
537 Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
538 L"\\");
539 if (!NT_SUCCESS (Status))
540 return Status;
541
542 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
543 &KeyObject->Name);
544 if (NT_SUCCESS (Status))
545 {
546 DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name);
547 }
548
549 return Status;
550 }
551
552
553 VOID
554 CmiAddKeyToList(PKEY_OBJECT ParentKey,
555 PKEY_OBJECT NewKey)
556 {
557
558 DPRINT("ParentKey %.08x\n", ParentKey);
559
560
561 if (ParentKey->SizeOfSubKeys <= ParentKey->NumberOfSubKeys)
562 {
563 PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
564 (ParentKey->NumberOfSubKeys + 1) * sizeof(ULONG));
565
566 if (ParentKey->NumberOfSubKeys > 0)
567 {
568 RtlCopyMemory (tmpSubKeys,
569 ParentKey->SubKeys,
570 ParentKey->NumberOfSubKeys * sizeof(ULONG));
571 }
572
573 if (ParentKey->SubKeys)
574 ExFreePool(ParentKey->SubKeys);
575
576 ParentKey->SubKeys = tmpSubKeys;
577 ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
578 }
579
580 /* FIXME: Please maintain the list in alphabetic order */
581 /* to allow a dichotomic search */
582 ParentKey->SubKeys[ParentKey->NumberOfSubKeys++] = NewKey;
583
584 DPRINT("Reference parent key: 0x%p\n", ParentKey);
585
586 ObReferenceObjectByPointer(ParentKey,
587 STANDARD_RIGHTS_REQUIRED,
588 NULL,
589 UserMode);
590 NewKey->ParentKey = ParentKey;
591 }
592
593
594 NTSTATUS
595 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
596 {
597 PKEY_OBJECT ParentKey;
598 DWORD Index;
599
600 ParentKey = KeyToRemove->ParentKey;
601 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
602 for (Index = 0; Index < ParentKey->NumberOfSubKeys; Index++)
603 {
604 if (ParentKey->SubKeys[Index] == KeyToRemove)
605 {
606 if (Index < ParentKey->NumberOfSubKeys-1)
607 RtlMoveMemory(&ParentKey->SubKeys[Index],
608 &ParentKey->SubKeys[Index + 1],
609 (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
610 ParentKey->NumberOfSubKeys--;
611
612 DPRINT("Dereference parent key: 0x%x\n", ParentKey);
613
614 ObDereferenceObject(ParentKey);
615 return STATUS_SUCCESS;
616 }
617 }
618
619 return STATUS_UNSUCCESSFUL;
620 }
621
622
623 NTSTATUS
624 CmiScanKeyList(PKEY_OBJECT Parent,
625 PUNICODE_STRING KeyName,
626 ULONG Attributes,
627 PKEY_OBJECT* ReturnedObject)
628 {
629 PKEY_OBJECT CurKey;
630 ULONG Index;
631
632 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
633 KeyName, &Parent->Name);
634
635 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
636 for (Index=0; Index < Parent->NumberOfSubKeys; Index++)
637 {
638 CurKey = Parent->SubKeys[Index];
639 if (Attributes & OBJ_CASE_INSENSITIVE)
640 {
641 if ((KeyName->Length == CurKey->Name.Length)
642 && (_wcsicmp(KeyName->Buffer, CurKey->Name.Buffer) == 0))
643 {
644 break;
645 }
646 }
647 else
648 {
649 if ((KeyName->Length == CurKey->Name.Length)
650 && (wcscmp(KeyName->Buffer, CurKey->Name.Buffer) == 0))
651 {
652 break;
653 }
654 }
655 }
656
657 if (Index < Parent->NumberOfSubKeys)
658 {
659 if (CurKey->Flags & KO_MARKED_FOR_DELETE)
660 {
661 *ReturnedObject = NULL;
662 return STATUS_UNSUCCESSFUL;
663 }
664 ObReferenceObject(CurKey);
665 *ReturnedObject = CurKey;
666 }
667 else
668 {
669 *ReturnedObject = NULL;
670 }
671 return STATUS_SUCCESS;
672 }
673
674
675 static NTSTATUS
676 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
677 PKEY_CELL KeyCell,
678 PUNICODE_STRING TargetPath)
679 {
680 UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
681 PVALUE_CELL ValueCell;
682 PDATA_CELL DataCell;
683 NTSTATUS Status;
684
685 DPRINT("CmiGetLinkTarget() called\n");
686
687 /* Get Value block of interest */
688 Status = CmiScanKeyForValue(RegistryHive,
689 KeyCell,
690 &LinkName,
691 &ValueCell,
692 NULL);
693 if (!NT_SUCCESS(Status))
694 {
695 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status);
696 return(Status);
697 }
698
699 if (ValueCell->DataType != REG_LINK)
700 {
701 DPRINT1("Type != REG_LINK\n!");
702 return(STATUS_UNSUCCESSFUL);
703 }
704
705 if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0)
706 {
707 TargetPath->Length = 0;
708 TargetPath->MaximumLength = ValueCell->DataSize + sizeof(WCHAR);
709 TargetPath->Buffer = ExAllocatePool(NonPagedPool,
710 TargetPath->MaximumLength);
711 }
712
713 TargetPath->Length = min(TargetPath->MaximumLength - sizeof(WCHAR),
714 (ULONG) ValueCell->DataSize);
715
716 if (ValueCell->DataSize > 0)
717 {
718 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
719 RtlCopyMemory(TargetPath->Buffer,
720 DataCell->Data,
721 TargetPath->Length);
722 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
723 }
724 else
725 {
726 RtlCopyMemory(TargetPath->Buffer,
727 &ValueCell->DataOffset,
728 TargetPath->Length);
729 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
730 }
731
732 DPRINT("TargetPath '%wZ'\n", TargetPath);
733
734 return(STATUS_SUCCESS);
735 }
736
737 /* EOF */