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