f6832471eaee83d0536ea761222037f77ccfa67d
[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%x\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 PSECURITY_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 {
455 DPRINT("CmiObjectSecurity() called\n");
456
457 switch (OperationCode)
458 {
459 case SetSecurityDescriptor:
460 DPRINT("Set security descriptor\n");
461 return STATUS_SUCCESS;
462
463 case QuerySecurityDescriptor:
464 DPRINT("Query security descriptor\n");
465 return CmiQuerySecurityDescriptor((PKEY_OBJECT)ObjectBody,
466 SecurityInformation,
467 SecurityDescriptor,
468 BufferLength);
469
470 case DeleteSecurityDescriptor:
471 DPRINT("Delete security descriptor\n");
472 return STATUS_SUCCESS;
473
474 case AssignSecurityDescriptor:
475 DPRINT("Assign security descriptor\n");
476 return CmiAssignSecurityDescriptor((PKEY_OBJECT)ObjectBody,
477 SecurityDescriptor);
478 }
479
480 return STATUS_UNSUCCESSFUL;
481 }
482
483
484 NTSTATUS STDCALL
485 CmiObjectQueryName (PVOID ObjectBody,
486 POBJECT_NAME_INFORMATION ObjectNameInfo,
487 ULONG Length,
488 PULONG ReturnLength)
489 {
490 POBJECT_NAME_INFORMATION LocalInfo;
491 PKEY_OBJECT KeyObject;
492 ULONG LocalReturnLength;
493 NTSTATUS Status;
494
495 DPRINT ("CmiObjectQueryName() called\n");
496
497 KeyObject = (PKEY_OBJECT)ObjectBody;
498
499 LocalInfo = ExAllocatePool (NonPagedPool,
500 sizeof(OBJECT_NAME_INFORMATION) +
501 MAX_PATH * sizeof(WCHAR));
502 if (LocalInfo == NULL)
503 return STATUS_INSUFFICIENT_RESOURCES;
504
505 if (KeyObject->ParentKey != KeyObject)
506 {
507 Status = ObQueryNameString (KeyObject->ParentKey,
508 LocalInfo,
509 MAX_PATH * sizeof(WCHAR),
510 &LocalReturnLength);
511 }
512 else
513 {
514 /* KeyObject is the root key */
515 Status = ObQueryNameString (HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(KeyObject))->Directory,
516 LocalInfo,
517 MAX_PATH * sizeof(WCHAR),
518 &LocalReturnLength);
519 }
520
521 if (!NT_SUCCESS (Status))
522 {
523 ExFreePool (LocalInfo);
524 return Status;
525 }
526 DPRINT ("Parent path: %wZ\n", &LocalInfo->Name);
527
528 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
529 &LocalInfo->Name);
530 ExFreePool (LocalInfo);
531 if (!NT_SUCCESS (Status))
532 return Status;
533
534 Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
535 L"\\");
536 if (!NT_SUCCESS (Status))
537 return Status;
538
539 Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
540 &KeyObject->Name);
541 if (NT_SUCCESS (Status))
542 {
543 DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name);
544 }
545
546 return Status;
547 }
548
549
550 VOID
551 CmiAddKeyToList(PKEY_OBJECT ParentKey,
552 PKEY_OBJECT NewKey)
553 {
554
555 DPRINT("ParentKey %.08x\n", ParentKey);
556
557
558 if (ParentKey->SizeOfSubKeys <= ParentKey->NumberOfSubKeys)
559 {
560 PKEY_OBJECT *tmpSubKeys = ExAllocatePool(NonPagedPool,
561 (ParentKey->NumberOfSubKeys + 1) * sizeof(ULONG));
562
563 if (ParentKey->NumberOfSubKeys > 0)
564 {
565 RtlCopyMemory (tmpSubKeys,
566 ParentKey->SubKeys,
567 ParentKey->NumberOfSubKeys * sizeof(ULONG));
568 }
569
570 if (ParentKey->SubKeys)
571 ExFreePool(ParentKey->SubKeys);
572
573 ParentKey->SubKeys = tmpSubKeys;
574 ParentKey->SizeOfSubKeys = ParentKey->NumberOfSubKeys + 1;
575 }
576
577 /* FIXME: Please maintain the list in alphabetic order */
578 /* to allow a dichotomic search */
579 ParentKey->SubKeys[ParentKey->NumberOfSubKeys++] = NewKey;
580
581 DPRINT("Reference parent key: 0x%x\n", ParentKey);
582
583 ObReferenceObjectByPointer(ParentKey,
584 STANDARD_RIGHTS_REQUIRED,
585 NULL,
586 UserMode);
587 NewKey->ParentKey = ParentKey;
588 }
589
590
591 NTSTATUS
592 CmiRemoveKeyFromList(PKEY_OBJECT KeyToRemove)
593 {
594 PKEY_OBJECT ParentKey;
595 DWORD Index;
596
597 ParentKey = KeyToRemove->ParentKey;
598 /* FIXME: If list maintained in alphabetic order, use dichotomic search */
599 for (Index = 0; Index < ParentKey->NumberOfSubKeys; Index++)
600 {
601 if (ParentKey->SubKeys[Index] == KeyToRemove)
602 {
603 if (Index < ParentKey->NumberOfSubKeys-1)
604 RtlMoveMemory(&ParentKey->SubKeys[Index],
605 &ParentKey->SubKeys[Index + 1],
606 (ParentKey->NumberOfSubKeys - Index - 1) * sizeof(PKEY_OBJECT));
607 ParentKey->NumberOfSubKeys--;
608
609 DPRINT("Dereference parent key: 0x%x\n", ParentKey);
610
611 ObDereferenceObject(ParentKey);
612 return STATUS_SUCCESS;
613 }
614 }
615
616 return STATUS_UNSUCCESSFUL;
617 }
618
619
620 NTSTATUS
621 CmiScanKeyList(PKEY_OBJECT Parent,
622 PUNICODE_STRING KeyName,
623 ULONG Attributes,
624 PKEY_OBJECT* ReturnedObject)
625 {
626 PKEY_OBJECT CurKey;
627 ULONG Index;
628
629 DPRINT("Scanning key list for: %wZ (Parent: %wZ)\n",
630 KeyName, &Parent->Name);
631
632 /* FIXME: if list maintained in alphabetic order, use dichotomic search */
633 for (Index=0; Index < Parent->NumberOfSubKeys; Index++)
634 {
635 CurKey = Parent->SubKeys[Index];
636 if (Attributes & OBJ_CASE_INSENSITIVE)
637 {
638 if ((KeyName->Length == CurKey->Name.Length)
639 && (_wcsicmp(KeyName->Buffer, CurKey->Name.Buffer) == 0))
640 {
641 break;
642 }
643 }
644 else
645 {
646 if ((KeyName->Length == CurKey->Name.Length)
647 && (wcscmp(KeyName->Buffer, CurKey->Name.Buffer) == 0))
648 {
649 break;
650 }
651 }
652 }
653
654 if (Index < Parent->NumberOfSubKeys)
655 {
656 if (CurKey->Flags & KO_MARKED_FOR_DELETE)
657 {
658 *ReturnedObject = NULL;
659 return STATUS_UNSUCCESSFUL;
660 }
661 ObReferenceObject(CurKey);
662 *ReturnedObject = CurKey;
663 }
664 else
665 {
666 *ReturnedObject = NULL;
667 }
668 return STATUS_SUCCESS;
669 }
670
671
672 static NTSTATUS
673 CmiGetLinkTarget(PREGISTRY_HIVE RegistryHive,
674 PKEY_CELL KeyCell,
675 PUNICODE_STRING TargetPath)
676 {
677 UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
678 PVALUE_CELL ValueCell;
679 PDATA_CELL DataCell;
680 NTSTATUS Status;
681
682 DPRINT("CmiGetLinkTarget() called\n");
683
684 /* Get Value block of interest */
685 Status = CmiScanKeyForValue(RegistryHive,
686 KeyCell,
687 &LinkName,
688 &ValueCell,
689 NULL);
690 if (!NT_SUCCESS(Status))
691 {
692 DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status);
693 return(Status);
694 }
695
696 if (ValueCell->DataType != REG_LINK)
697 {
698 DPRINT1("Type != REG_LINK\n!");
699 return(STATUS_UNSUCCESSFUL);
700 }
701
702 if (TargetPath->Buffer == NULL && TargetPath->MaximumLength == 0)
703 {
704 TargetPath->Length = 0;
705 TargetPath->MaximumLength = ValueCell->DataSize + sizeof(WCHAR);
706 TargetPath->Buffer = ExAllocatePool(NonPagedPool,
707 TargetPath->MaximumLength);
708 }
709
710 TargetPath->Length = min(TargetPath->MaximumLength - sizeof(WCHAR),
711 (ULONG) ValueCell->DataSize);
712
713 if (ValueCell->DataSize > 0)
714 {
715 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
716 RtlCopyMemory(TargetPath->Buffer,
717 DataCell->Data,
718 TargetPath->Length);
719 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
720 }
721 else
722 {
723 RtlCopyMemory(TargetPath->Buffer,
724 &ValueCell->DataOffset,
725 TargetPath->Length);
726 TargetPath->Buffer[TargetPath->Length / sizeof(WCHAR)] = 0;
727 }
728
729 DPRINT("TargetPath '%wZ'\n", TargetPath);
730
731 return(STATUS_SUCCESS);
732 }
733
734 /* EOF */