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