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