fix code that depends on GCC's void* pointer arithmetic extension
[reactos.git] / reactos / lib / rtl / registry.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Rtl registry functions
6 * FILE: lib/rtl/registry.c
7 * PROGRAMER: Eric Kohl
8 * REVISION HISTORY:
9 * 2000/08/11: Created
10 */
11
12 /*
13 * TODO:
14 * - finish RtlQueryRegistryValues()
15 * - support RTL_QUERY_REGISTRY_DELETE
16 */
17
18 /* INCLUDES ****************************************************************/
19
20 #define __NTDRIVER__
21 #include "rtl.h"
22
23 #define NDEBUG
24 #include <debug.h>
25
26
27 /* FUNCTIONS ***************************************************************/
28
29 static NTSTATUS
30 RtlpGetRegistryHandle(ULONG RelativeTo,
31 PWSTR Path,
32 BOOLEAN Create,
33 PHANDLE KeyHandle)
34 {
35 UNICODE_STRING KeyPath;
36 UNICODE_STRING KeyName;
37 WCHAR KeyBuffer[MAX_PATH];
38 OBJECT_ATTRIBUTES ObjectAttributes;
39 NTSTATUS Status;
40
41 DPRINT("RtlpGetRegistryHandle()\n");
42
43 if (RelativeTo & RTL_REGISTRY_HANDLE)
44 {
45 Status = ZwDuplicateObject(NtCurrentProcess(),
46 (HANDLE)Path,
47 NtCurrentProcess(),
48 KeyHandle,
49 0,
50 FALSE,
51 DUPLICATE_SAME_ACCESS);
52 #ifndef NDEBUG
53 if(!NT_SUCCESS(Status))
54 {
55 DPRINT("ZwDuplicateObject() failed! Status: 0x%x\n", Status);
56 }
57 #endif
58
59 return(Status);
60 }
61
62 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
63 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
64
65 if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
66 {
67 DPRINT("Invalid relative flag, parameter invalid!\n");
68 return(STATUS_INVALID_PARAMETER);
69 }
70
71 KeyName.Length = 0;
72 KeyName.MaximumLength = sizeof(KeyBuffer);
73 KeyName.Buffer = KeyBuffer;
74 KeyBuffer[0] = 0;
75
76 switch (RelativeTo)
77 {
78 case RTL_REGISTRY_ABSOLUTE:
79 /* nothing to prefix! */
80 break;
81
82 case RTL_REGISTRY_SERVICES:
83 RtlAppendUnicodeToString(&KeyName,
84 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
85 break;
86
87 case RTL_REGISTRY_CONTROL:
88 RtlAppendUnicodeToString(&KeyName,
89 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
90 break;
91
92 case RTL_REGISTRY_WINDOWS_NT:
93 RtlAppendUnicodeToString(&KeyName,
94 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
95 break;
96
97 case RTL_REGISTRY_DEVICEMAP:
98 RtlAppendUnicodeToString(&KeyName,
99 L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
100 break;
101
102 case RTL_REGISTRY_USER:
103 Status = RtlFormatCurrentUserKeyPath (&KeyPath);
104 if (!NT_SUCCESS(Status))
105 return(Status);
106 RtlAppendUnicodeStringToString (&KeyName,
107 &KeyPath);
108 RtlFreeUnicodeString (&KeyPath);
109 RtlAppendUnicodeToString (&KeyName,
110 L"\\");
111 break;
112 }
113
114 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
115 {
116 Path++;
117 }
118 RtlAppendUnicodeToString(&KeyName,
119 Path);
120
121 DPRINT("KeyName %wZ\n", &KeyName);
122
123 InitializeObjectAttributes(&ObjectAttributes,
124 &KeyName,
125 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
126 NULL,
127 NULL);
128
129 if (Create)
130 {
131 Status = ZwCreateKey(KeyHandle,
132 KEY_ALL_ACCESS,
133 &ObjectAttributes,
134 0,
135 NULL,
136 0,
137 NULL);
138 }
139 else
140 {
141 Status = ZwOpenKey(KeyHandle,
142 KEY_ALL_ACCESS,
143 &ObjectAttributes);
144 }
145
146 #ifndef NDEBUG
147 if(!NT_SUCCESS(Status))
148 {
149 DPRINT("%s failed! Status: 0x%x\n", (Create ? "ZwCreateKey" : "ZwOpenKey"), Status);
150 }
151 #endif
152
153 return(Status);
154 }
155
156
157 /*
158 * @implemented
159 */
160 NTSTATUS STDCALL
161 RtlCheckRegistryKey(IN ULONG RelativeTo,
162 IN PWSTR Path)
163 {
164 HANDLE KeyHandle;
165 NTSTATUS Status;
166
167 PAGED_CODE_RTL();
168
169 Status = RtlpGetRegistryHandle(RelativeTo,
170 Path,
171 FALSE,
172 &KeyHandle);
173 if (!NT_SUCCESS(Status))
174 return(Status);
175
176 ZwClose(KeyHandle);
177
178 return(STATUS_SUCCESS);
179 }
180
181
182 /*
183 * @implemented
184 */
185 NTSTATUS STDCALL
186 RtlCreateRegistryKey(IN ULONG RelativeTo,
187 IN PWSTR Path)
188 {
189 HANDLE KeyHandle;
190 NTSTATUS Status;
191
192 PAGED_CODE_RTL();
193
194 Status = RtlpGetRegistryHandle(RelativeTo,
195 Path,
196 TRUE,
197 &KeyHandle);
198 if (!NT_SUCCESS(Status))
199 return(Status);
200
201 ZwClose(KeyHandle);
202
203 return(STATUS_SUCCESS);
204 }
205
206
207 /*
208 * @implemented
209 */
210 NTSTATUS STDCALL
211 RtlDeleteRegistryValue(IN ULONG RelativeTo,
212 IN PCWSTR Path,
213 IN PCWSTR ValueName)
214 {
215 HANDLE KeyHandle;
216 NTSTATUS Status;
217 UNICODE_STRING Name;
218
219 PAGED_CODE_RTL();
220
221 Status = RtlpGetRegistryHandle(RelativeTo,
222 (PWSTR)Path,
223 FALSE,
224 &KeyHandle);
225 if (!NT_SUCCESS(Status))
226 return(Status);
227
228 RtlInitUnicodeString(&Name,
229 ValueName);
230
231 Status = ZwDeleteValueKey(KeyHandle,
232 &Name);
233
234 ZwClose(KeyHandle);
235
236 return(Status);
237 }
238
239
240 /*
241 * @implemented
242 */
243 NTSTATUS STDCALL
244 RtlFormatCurrentUserKeyPath (OUT PUNICODE_STRING KeyPath)
245 {
246 HANDLE TokenHandle;
247 UCHAR Buffer[256];
248 PSID_AND_ATTRIBUTES SidBuffer;
249 ULONG Length;
250 UNICODE_STRING SidString;
251 NTSTATUS Status;
252
253 PAGED_CODE_RTL();
254
255 DPRINT ("RtlFormatCurrentUserKeyPath() called\n");
256
257 Status = ZwOpenThreadToken (NtCurrentThread (),
258 TOKEN_QUERY,
259 TRUE,
260 &TokenHandle);
261 if (!NT_SUCCESS (Status))
262 {
263 if (Status != STATUS_NO_TOKEN)
264 {
265 DPRINT1 ("ZwOpenThreadToken() failed (Status %lx)\n", Status);
266 return Status;
267 }
268
269 Status = ZwOpenProcessToken (NtCurrentProcess (),
270 TOKEN_QUERY,
271 &TokenHandle);
272 if (!NT_SUCCESS (Status))
273 {
274 DPRINT1 ("ZwOpenProcessToken() failed (Status %lx)\n", Status);
275 return Status;
276 }
277 }
278
279 SidBuffer = (PSID_AND_ATTRIBUTES)Buffer;
280 Status = ZwQueryInformationToken (TokenHandle,
281 TokenUser,
282 (PVOID)SidBuffer,
283 256,
284 &Length);
285 ZwClose (TokenHandle);
286 if (!NT_SUCCESS(Status))
287 {
288 DPRINT1 ("ZwQueryInformationToken() failed (Status %lx)\n", Status);
289 return Status;
290 }
291
292 Status = RtlConvertSidToUnicodeString (&SidString,
293 SidBuffer[0].Sid,
294 TRUE);
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT1 ("RtlConvertSidToUnicodeString() failed (Status %lx)\n", Status);
298 return Status;
299 }
300
301 DPRINT ("SidString: '%wZ'\n", &SidString);
302
303 Length = SidString.Length + sizeof(L"\\Registry\\User\\");
304 DPRINT ("Length: %lu\n", Length);
305
306 KeyPath->Length = 0;
307 KeyPath->MaximumLength = Length;
308 KeyPath->Buffer = ExAllocatePool (PagedPool,
309 KeyPath->MaximumLength);
310 if (KeyPath->Buffer == NULL)
311 {
312 DPRINT1 ("ExAllocatePool() failed\n");
313 RtlFreeUnicodeString (&SidString);
314 return STATUS_NO_TOKEN;
315 }
316
317 RtlAppendUnicodeToString (KeyPath,
318 L"\\Registry\\User\\");
319 RtlAppendUnicodeStringToString (KeyPath,
320 &SidString);
321 RtlFreeUnicodeString (&SidString);
322
323 return STATUS_SUCCESS;
324 }
325
326
327 /*
328 * @implemented
329 */
330 NTSTATUS STDCALL
331 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
332 OUT PHANDLE KeyHandle)
333 {
334 OBJECT_ATTRIBUTES ObjectAttributes;
335 UNICODE_STRING KeyPath;
336 NTSTATUS Status;
337
338 PAGED_CODE_RTL();
339
340 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
341 if (NT_SUCCESS(Status))
342 {
343 InitializeObjectAttributes(&ObjectAttributes,
344 &KeyPath,
345 OBJ_CASE_INSENSITIVE,
346 NULL,
347 NULL);
348 Status = ZwOpenKey(KeyHandle,
349 DesiredAccess,
350 &ObjectAttributes);
351 RtlFreeUnicodeString(&KeyPath);
352 if (NT_SUCCESS(Status))
353 {
354 return STATUS_SUCCESS;
355 }
356 }
357
358 RtlInitUnicodeString (&KeyPath,
359 L"\\Registry\\User\\.Default");
360 InitializeObjectAttributes(&ObjectAttributes,
361 &KeyPath,
362 OBJ_CASE_INSENSITIVE,
363 NULL,
364 NULL);
365 Status = ZwOpenKey(KeyHandle,
366 DesiredAccess,
367 &ObjectAttributes);
368
369 return Status;
370 }
371
372
373 /*
374 * @unimplemented
375 */
376 NTSTATUS STDCALL
377 RtlQueryRegistryValues(IN ULONG RelativeTo,
378 IN PCWSTR Path,
379 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
380 IN PVOID Context,
381 IN PVOID Environment OPTIONAL)
382 {
383 NTSTATUS Status;
384 HANDLE BaseKeyHandle;
385 HANDLE CurrentKeyHandle;
386 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
387 OBJECT_ATTRIBUTES ObjectAttributes;
388 UNICODE_STRING KeyName;
389 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
390 PKEY_VALUE_FULL_INFORMATION FullValueInfo;
391 ULONG BufferSize;
392 ULONG ResultSize;
393 ULONG Index;
394 ULONG StringLen;
395 ULONG ValueNameSize;
396 PWSTR StringPtr;
397 PWSTR ExpandBuffer;
398 PWSTR ValueName;
399 UNICODE_STRING EnvValue;
400 UNICODE_STRING EnvExpandedValue;
401
402 PAGED_CODE_RTL();
403
404 DPRINT("RtlQueryRegistryValues() called\n");
405
406 Status = RtlpGetRegistryHandle(RelativeTo,
407 (PWSTR)Path,
408 FALSE,
409 &BaseKeyHandle);
410 if (!NT_SUCCESS(Status))
411 {
412 DPRINT("RtlpGetRegistryHandle() failed (Status %lx)\n", Status);
413 return(Status);
414 }
415
416 CurrentKeyHandle = BaseKeyHandle;
417 QueryEntry = QueryTable;
418 while ((QueryEntry->QueryRoutine != NULL) ||
419 (QueryEntry->Name != NULL))
420 {
421 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
422 (BaseKeyHandle != CurrentKeyHandle))
423 {
424 ZwClose(CurrentKeyHandle);
425 CurrentKeyHandle = BaseKeyHandle;
426 }
427
428 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
429 {
430 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
431
432 RtlInitUnicodeString(&KeyName,
433 QueryEntry->Name);
434 InitializeObjectAttributes(&ObjectAttributes,
435 &KeyName,
436 OBJ_CASE_INSENSITIVE,
437 BaseKeyHandle,
438 NULL);
439 Status = ZwOpenKey(&CurrentKeyHandle,
440 KEY_ALL_ACCESS,
441 &ObjectAttributes);
442 if (!NT_SUCCESS(Status))
443 break;
444 }
445 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
446 {
447 DPRINT("Query value directly: %S\n", QueryEntry->Name);
448
449 RtlInitUnicodeString(&KeyName,
450 QueryEntry->Name);
451
452 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
453 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
454 if (ValueInfo == NULL)
455 {
456 Status = STATUS_NO_MEMORY;
457 break;
458 }
459
460 Status = ZwQueryValueKey(CurrentKeyHandle,
461 &KeyName,
462 KeyValuePartialInformation,
463 ValueInfo,
464 BufferSize,
465 &ResultSize);
466 if (!NT_SUCCESS(Status))
467 {
468 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
469 {
470 ExFreePool(ValueInfo);
471 Status = STATUS_OBJECT_NAME_NOT_FOUND;
472 break;
473 }
474
475 if (QueryEntry->DefaultType == REG_SZ)
476 {
477 PUNICODE_STRING ValueString;
478 PUNICODE_STRING SourceString;
479
480 SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
481 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
482 if (ValueString->Buffer == NULL)
483 {
484 ValueString->Length = SourceString->Length;
485 ValueString->MaximumLength = SourceString->MaximumLength;
486 ValueString->Buffer = ExAllocatePool(PagedPool, BufferSize);
487 if (!ValueString->Buffer)
488 break;
489 ValueString->Buffer[0] = 0;
490 memcpy(ValueString->Buffer,
491 SourceString->Buffer,
492 SourceString->MaximumLength);
493 }
494 else
495 {
496 ValueString->Length = min(SourceString->Length,
497 ValueString->MaximumLength - sizeof(WCHAR));
498 memcpy(ValueString->Buffer,
499 SourceString->Buffer,
500 ValueString->Length);
501 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
502 }
503 }
504 else
505 {
506 memcpy(QueryEntry->EntryContext,
507 QueryEntry->DefaultData,
508 QueryEntry->DefaultLength);
509 }
510 Status = STATUS_SUCCESS;
511 }
512 else
513 {
514 if ((ValueInfo->Type == REG_SZ) ||
515 (ValueInfo->Type == REG_MULTI_SZ) ||
516 (ValueInfo->Type == REG_EXPAND_SZ && (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND)))
517 {
518 PUNICODE_STRING ValueString;
519
520 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
521 if (ValueString->Buffer == NULL)
522 {
523 ValueString->MaximumLength = ValueInfo->DataLength;
524 ValueString->Buffer = ExAllocatePool(PagedPool, ValueString->MaximumLength);
525 if (ValueString->Buffer == NULL)
526 {
527 Status = STATUS_INSUFFICIENT_RESOURCES;
528 break;
529 }
530 ValueString->Buffer[0] = 0;
531 }
532 ValueString->Length = min(ValueInfo->DataLength,
533 ValueString->MaximumLength) - sizeof(WCHAR);
534 memcpy(ValueString->Buffer,
535 ValueInfo->Data,
536 ValueString->Length);
537 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
538 }
539 else if (ValueInfo->Type == REG_EXPAND_SZ)
540 {
541 PUNICODE_STRING ValueString;
542
543 DPRINT("Expand REG_EXPAND_SZ type\n");
544
545 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
546
547 ExpandBuffer = ExAllocatePool(PagedPool, ValueInfo->DataLength * 2);
548 if (ExpandBuffer == NULL)
549 {
550 Status = STATUS_NO_MEMORY;
551 break;
552 }
553
554 RtlInitUnicodeString(&EnvValue,
555 (PWSTR)ValueInfo->Data);
556 EnvExpandedValue.Length = 0;
557 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2;
558 EnvExpandedValue.Buffer = ExpandBuffer;
559 *ExpandBuffer = 0;
560
561 RtlExpandEnvironmentStrings_U(Environment,
562 &EnvValue,
563 &EnvExpandedValue,
564 &StringLen);
565
566 if (ValueString->Buffer == NULL)
567 {
568 ValueString->MaximumLength = EnvExpandedValue.Length + sizeof(WCHAR);
569 ValueString->Length = EnvExpandedValue.Length;
570 ValueString->Buffer = ExAllocatePool(PagedPool, ValueString->MaximumLength);
571 if (ValueString->Buffer == NULL)
572 {
573 Status = STATUS_INSUFFICIENT_RESOURCES;
574 break;
575 }
576 }
577 else
578 {
579 ValueString->Length = min(EnvExpandedValue.Length,
580 ValueString->MaximumLength - sizeof(WCHAR));
581 }
582
583 memcpy(ValueString->Buffer,
584 EnvExpandedValue.Buffer,
585 ValueString->Length);
586 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
587
588 ExFreePool(ExpandBuffer);
589 }
590 else
591 {
592 memcpy(QueryEntry->EntryContext,
593 ValueInfo->Data,
594 ValueInfo->DataLength);
595 }
596 }
597
598 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
599 {
600 DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
601
602 }
603
604 ExFreePool(ValueInfo);
605 }
606 else
607 {
608 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
609 if (QueryEntry->Name != NULL)
610 {
611 RtlInitUnicodeString(&KeyName,
612 QueryEntry->Name);
613
614 BufferSize = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + 4096;
615 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
616 if (ValueInfo == NULL)
617 {
618 Status = STATUS_NO_MEMORY;
619 break;
620 }
621
622 Status = ZwQueryValueKey(CurrentKeyHandle,
623 &KeyName,
624 KeyValuePartialInformation,
625 ValueInfo,
626 BufferSize,
627 &ResultSize);
628 if (!NT_SUCCESS(Status))
629 {
630 if (!(QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
631 {
632 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
633 QueryEntry->DefaultType,
634 QueryEntry->DefaultData,
635 QueryEntry->DefaultLength,
636 Context,
637 QueryEntry->EntryContext);
638 }
639 }
640 else if ((ValueInfo->Type == REG_MULTI_SZ) &&
641 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
642 {
643 DPRINT("Expand REG_MULTI_SZ type\n");
644 StringPtr = (PWSTR)ValueInfo->Data;
645 while (*StringPtr != 0)
646 {
647 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
648 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
649 REG_SZ,
650 (PVOID)StringPtr,
651 StringLen,
652 Context,
653 QueryEntry->EntryContext);
654 if(!NT_SUCCESS(Status))
655 break;
656 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
657 }
658 }
659 else if ((ValueInfo->Type == REG_EXPAND_SZ) &&
660 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
661 {
662 DPRINT("Expand REG_EXPAND_SZ type\n");
663
664 ExpandBuffer = ExAllocatePool(PagedPool, ValueInfo->DataLength * 2);
665 if (ExpandBuffer == NULL)
666 {
667 Status = STATUS_NO_MEMORY;
668 break;
669 }
670
671 RtlInitUnicodeString(&EnvValue,
672 (PWSTR)ValueInfo->Data);
673 EnvExpandedValue.Length = 0;
674 EnvExpandedValue.MaximumLength = ValueInfo->DataLength * 2 * sizeof(WCHAR);
675 EnvExpandedValue.Buffer = ExpandBuffer;
676 *ExpandBuffer = 0;
677
678 RtlExpandEnvironmentStrings_U(Environment,
679 &EnvValue,
680 &EnvExpandedValue,
681 &StringLen);
682
683 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
684 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
685 REG_SZ,
686 (PVOID)ExpandBuffer,
687 StringLen,
688 Context,
689 QueryEntry->EntryContext);
690
691 ExFreePool(ExpandBuffer);
692 }
693 else
694 {
695 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
696 ValueInfo->Type,
697 ValueInfo->Data,
698 ValueInfo->DataLength,
699 Context,
700 QueryEntry->EntryContext);
701 }
702
703 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
704 {
705 DPRINT1("FIXME: Delete value: %S\n", QueryEntry->Name);
706
707 }
708
709 ExFreePool(ValueInfo);
710 if (!NT_SUCCESS(Status))
711 break;
712 }
713 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
714 {
715 DPRINT("Simple callback\n");
716 Status = QueryEntry->QueryRoutine(NULL,
717 REG_NONE,
718 NULL,
719 0,
720 Context,
721 QueryEntry->EntryContext);
722 if (!NT_SUCCESS(Status))
723 break;
724 }
725 else
726 {
727 DPRINT("Enumerate values\n");
728
729 BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
730 FullValueInfo = ExAllocatePool(PagedPool, BufferSize);
731 if (FullValueInfo == NULL)
732 {
733 Status = STATUS_NO_MEMORY;
734 break;
735 }
736 ValueNameSize = 256 * sizeof(WCHAR);
737 ValueName = ExAllocatePool(PagedPool, ValueNameSize);
738 if (ValueName == NULL)
739 {
740 Status = STATUS_NO_MEMORY;
741 break;
742 }
743 Index = 0;
744 while (TRUE)
745 {
746 Status = ZwEnumerateValueKey(CurrentKeyHandle,
747 Index,
748 KeyValueFullInformation,
749 FullValueInfo,
750 BufferSize,
751 &ResultSize);
752 if (!NT_SUCCESS(Status))
753 {
754 if ((Status == STATUS_NO_MORE_ENTRIES) &&
755 (Index == 0) &&
756 (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
757 {
758 Status = STATUS_OBJECT_NAME_NOT_FOUND;
759 }
760 else if (Status == STATUS_NO_MORE_ENTRIES)
761 {
762 Status = STATUS_SUCCESS;
763 }
764 break;
765 }
766
767 if (FullValueInfo->NameLength > ValueNameSize - sizeof(WCHAR))
768 {
769 /* Should not happen, because the name length is limited to 255 characters */
770 ExFreePool(ValueName);
771 ValueNameSize = FullValueInfo->NameLength + sizeof(WCHAR);
772 ValueName = ExAllocatePool(PagedPool, ValueNameSize);
773 if (ValueName == NULL)
774 {
775 Status = STATUS_NO_MEMORY;
776 break;
777 }
778 }
779
780 memcpy(ValueName,
781 FullValueInfo->Name,
782 FullValueInfo->NameLength);
783 ValueName[FullValueInfo->NameLength / sizeof(WCHAR)] = 0;
784
785 DPRINT("FullValueInfo->Type: %lu\n", FullValueInfo->Type);
786 if ((FullValueInfo->Type == REG_MULTI_SZ) &&
787 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
788 {
789 DPRINT("Expand REG_MULTI_SZ type\n");
790 StringPtr = (PWSTR)((ULONG_PTR)FullValueInfo + FullValueInfo->DataOffset);
791 while (*StringPtr != 0)
792 {
793 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
794 Status = QueryEntry->QueryRoutine(ValueName,
795 REG_SZ,
796 (PVOID)StringPtr,
797 StringLen,
798 Context,
799 QueryEntry->EntryContext);
800 if(!NT_SUCCESS(Status))
801 break;
802 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
803 }
804 }
805 else if ((FullValueInfo->Type == REG_EXPAND_SZ) &&
806 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
807 {
808 DPRINT("Expand REG_EXPAND_SZ type\n");
809
810 StringPtr = (PWSTR)((ULONG_PTR)FullValueInfo + FullValueInfo->DataOffset);
811 ExpandBuffer = ExAllocatePool(PagedPool, FullValueInfo->DataLength * 2);
812 if (ExpandBuffer == NULL)
813 {
814 Status = STATUS_NO_MEMORY;
815 break;
816 }
817
818 RtlInitUnicodeString(&EnvValue,
819 StringPtr);
820 EnvExpandedValue.Length = 0;
821 EnvExpandedValue.MaximumLength = FullValueInfo->DataLength * 2;
822 EnvExpandedValue.Buffer = ExpandBuffer;
823 *ExpandBuffer = 0;
824
825 RtlExpandEnvironmentStrings_U(Environment,
826 &EnvValue,
827 &EnvExpandedValue,
828 &StringLen);
829
830 StringLen = (wcslen(ExpandBuffer) + 1) * sizeof(WCHAR);
831 Status = QueryEntry->QueryRoutine(ValueName,
832 REG_SZ,
833 (PVOID)ExpandBuffer,
834 StringLen,
835 Context,
836 QueryEntry->EntryContext);
837
838 ExFreePool(ExpandBuffer);
839 }
840 else
841 {
842 Status = QueryEntry->QueryRoutine(ValueName,
843 FullValueInfo->Type,
844 (PVOID)((ULONG_PTR)FullValueInfo + FullValueInfo->DataOffset),
845 FullValueInfo->DataLength,
846 Context,
847 QueryEntry->EntryContext);
848 }
849
850 if (!NT_SUCCESS(Status))
851 break;
852
853 /* FIXME: How will these be deleted? */
854
855 Index++;
856 }
857
858 ExFreePool(FullValueInfo);
859 ExFreePool(ValueName);
860 if (!NT_SUCCESS(Status))
861 break;
862 }
863 }
864
865 QueryEntry++;
866 }
867
868 if (CurrentKeyHandle != BaseKeyHandle)
869 ZwClose(CurrentKeyHandle);
870
871 ZwClose(BaseKeyHandle);
872
873 return(Status);
874 }
875
876
877 /*
878 * @implemented
879 */
880 NTSTATUS STDCALL
881 RtlWriteRegistryValue(IN ULONG RelativeTo,
882 IN PCWSTR Path,
883 IN PCWSTR ValueName,
884 IN ULONG ValueType,
885 IN PVOID ValueData,
886 IN ULONG ValueLength)
887 {
888 HANDLE KeyHandle;
889 NTSTATUS Status;
890 UNICODE_STRING Name;
891
892 PAGED_CODE_RTL();
893
894 Status = RtlpGetRegistryHandle(RelativeTo,
895 (PWSTR)Path,
896 TRUE,
897 &KeyHandle);
898 if (!NT_SUCCESS(Status))
899 {
900 DPRINT("RtlpGetRegistryHandle() failed! Status: 0x%x\n", Status);
901 return(Status);
902 }
903
904 RtlInitUnicodeString(&Name,
905 ValueName);
906
907 Status = ZwSetValueKey(KeyHandle,
908 &Name,
909 0,
910 ValueType,
911 ValueData,
912 ValueLength);
913 if (!NT_SUCCESS(Status))
914 {
915 DPRINT1("ZwSetValueKey() failed! Status: 0x%x\n", Status);
916 }
917
918 ZwClose(KeyHandle);
919
920 return(Status);
921 }
922
923
924 /*
925 * @implemented
926 */
927 NTSTATUS STDCALL
928 RtlpNtCreateKey(OUT HANDLE KeyHandle,
929 IN ACCESS_MASK DesiredAccess,
930 IN POBJECT_ATTRIBUTES ObjectAttributes,
931 IN ULONG Unused1,
932 OUT PULONG Disposition,
933 IN ULONG Unused2)
934 {
935 if (ObjectAttributes != NULL)
936 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
937
938 return(ZwCreateKey(KeyHandle,
939 DesiredAccess,
940 ObjectAttributes,
941 0,
942 NULL,
943 0,
944 Disposition));
945 }
946
947
948 /*
949 * @implemented
950 */
951 NTSTATUS STDCALL
952 RtlpNtEnumerateSubKey(IN HANDLE KeyHandle,
953 OUT PUNICODE_STRING SubKeyName,
954 IN ULONG Index,
955 IN ULONG Unused)
956 {
957 PKEY_BASIC_INFORMATION KeyInfo = NULL;
958 ULONG BufferLength = 0;
959 ULONG ReturnedLength;
960 NTSTATUS Status;
961
962 if (SubKeyName->MaximumLength != 0)
963 {
964 BufferLength = SubKeyName->MaximumLength +
965 sizeof(KEY_BASIC_INFORMATION);
966 KeyInfo = ExAllocatePool(PagedPool, BufferLength);
967 if (KeyInfo == NULL)
968 return(STATUS_NO_MEMORY);
969 }
970
971 Status = ZwEnumerateKey(KeyHandle,
972 Index,
973 KeyBasicInformation,
974 KeyInfo,
975 BufferLength,
976 &ReturnedLength);
977 if (NT_SUCCESS(Status))
978 {
979 if (KeyInfo->NameLength + sizeof(WCHAR) <= SubKeyName->MaximumLength)
980 {
981 memmove(SubKeyName->Buffer,
982 KeyInfo->Name,
983 KeyInfo->NameLength);
984 SubKeyName->Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
985 SubKeyName->Length = KeyInfo->NameLength;
986 }
987 else
988 {
989 Status = STATUS_BUFFER_OVERFLOW;
990 }
991 }
992
993 if (KeyInfo != NULL)
994 {
995 ExFreePool(KeyInfo);
996 }
997
998 return(Status);
999 }
1000
1001
1002 /*
1003 * @implemented
1004 */
1005 NTSTATUS STDCALL
1006 RtlpNtMakeTemporaryKey(IN HANDLE KeyHandle)
1007 {
1008 return(ZwDeleteKey(KeyHandle));
1009 }
1010
1011
1012 /*
1013 * @implemented
1014 */
1015 NTSTATUS STDCALL
1016 RtlpNtOpenKey(OUT HANDLE KeyHandle,
1017 IN ACCESS_MASK DesiredAccess,
1018 IN POBJECT_ATTRIBUTES ObjectAttributes,
1019 IN ULONG Unused)
1020 {
1021 if (ObjectAttributes != NULL)
1022 ObjectAttributes->Attributes &= ~(OBJ_PERMANENT | OBJ_EXCLUSIVE);
1023
1024 return(ZwOpenKey(KeyHandle,
1025 DesiredAccess,
1026 ObjectAttributes));
1027 }
1028
1029
1030 /*
1031 * @implemented
1032 */
1033 NTSTATUS STDCALL
1034 RtlpNtQueryValueKey(IN HANDLE KeyHandle,
1035 OUT PULONG Type OPTIONAL,
1036 OUT PVOID Data OPTIONAL,
1037 IN OUT PULONG DataLength OPTIONAL,
1038 IN ULONG Unused)
1039 {
1040 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
1041 UNICODE_STRING ValueName;
1042 ULONG BufferLength;
1043 ULONG ReturnedLength;
1044 NTSTATUS Status;
1045
1046 RtlInitUnicodeString(&ValueName,
1047 NULL);
1048
1049 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
1050 if (DataLength != NULL)
1051 BufferLength = *DataLength;
1052
1053 ValueInfo = ExAllocatePool(PagedPool, BufferLength);
1054 if (ValueInfo == NULL)
1055 return(STATUS_NO_MEMORY);
1056
1057 Status = ZwQueryValueKey(KeyHandle,
1058 &ValueName,
1059 KeyValuePartialInformation,
1060 ValueInfo,
1061 BufferLength,
1062 &ReturnedLength);
1063 if (NT_SUCCESS(Status))
1064 {
1065 if (DataLength != NULL)
1066 *DataLength = ValueInfo->DataLength;
1067
1068 if (Type != NULL)
1069 *Type = ValueInfo->Type;
1070
1071 if (Data != NULL)
1072 {
1073 memmove(Data,
1074 ValueInfo->Data,
1075 ValueInfo->DataLength);
1076 }
1077 }
1078
1079 ExFreePool(ValueInfo);
1080
1081 return(Status);
1082 }
1083
1084
1085 /*
1086 * @implemented
1087 */
1088 NTSTATUS STDCALL
1089 RtlpNtSetValueKey(IN HANDLE KeyHandle,
1090 IN ULONG Type,
1091 IN PVOID Data,
1092 IN ULONG DataLength)
1093 {
1094 UNICODE_STRING ValueName;
1095
1096 RtlInitUnicodeString(&ValueName,
1097 NULL);
1098 return(ZwSetValueKey(KeyHandle,
1099 &ValueName,
1100 0,
1101 Type,
1102 Data,
1103 DataLength));
1104 }
1105
1106 /* EOF */