2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/rtlfunc.c
5 * PURPOSE: Rtlxxx function for registry access
9 /* INCLUDES *****************************************************************/
11 #include <ddk/ntddk.h>
12 #include <rosrtl/string.h>
13 #include <rosrtl/minmax.h>
19 #include <internal/debug.h>
23 /* FUNCTIONS ****************************************************************/
27 RtlpGetRegistryHandle(ULONG RelativeTo
,
32 UNICODE_STRING KeyName
;
33 WCHAR KeyBuffer
[MAX_PATH
];
34 OBJECT_ATTRIBUTES ObjectAttributes
;
37 if (RelativeTo
& RTL_REGISTRY_HANDLE
)
39 Status
= NtDuplicateObject(NtCurrentProcess(),
45 DUPLICATE_SAME_ACCESS
);
49 if (RelativeTo
& RTL_REGISTRY_OPTIONAL
)
50 RelativeTo
&= ~RTL_REGISTRY_OPTIONAL
;
52 if (RelativeTo
>= RTL_REGISTRY_MAXIMUM
)
53 return STATUS_INVALID_PARAMETER
;
56 KeyName
.MaximumLength
= MAX_PATH
;
57 KeyName
.Buffer
= KeyBuffer
;
62 case RTL_REGISTRY_SERVICES
:
63 RtlAppendUnicodeToString(&KeyName
,
64 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
67 case RTL_REGISTRY_CONTROL
:
68 RtlAppendUnicodeToString(&KeyName
,
69 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
72 case RTL_REGISTRY_WINDOWS_NT
:
73 RtlAppendUnicodeToString(&KeyName
,
74 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
77 case RTL_REGISTRY_DEVICEMAP
:
78 RtlAppendUnicodeToString(&KeyName
,
79 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\");
82 case RTL_REGISTRY_USER
:
83 Status
= RtlFormatCurrentUserKeyPath(&KeyName
);
84 if (!NT_SUCCESS(Status
))
88 /* ReactOS specific */
89 case RTL_REGISTRY_ENUM
:
90 RtlAppendUnicodeToString(&KeyName
,
91 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
95 if (Path
[0] == L
'\\' && RelativeTo
!= RTL_REGISTRY_ABSOLUTE
)
99 RtlAppendUnicodeToString(&KeyName
,
102 DPRINT("KeyName '%wZ'\n", &KeyName
);
104 InitializeObjectAttributes(&ObjectAttributes
,
106 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
112 Status
= NtCreateKey(KeyHandle
,
122 Status
= NtOpenKey(KeyHandle
,
135 RtlCheckRegistryKey(IN ULONG RelativeTo
,
141 Status
= RtlpGetRegistryHandle(RelativeTo
,
145 if (!NT_SUCCESS(Status
))
150 return(STATUS_SUCCESS
);
158 RtlCreateRegistryKey(IN ULONG RelativeTo
,
164 Status
= RtlpGetRegistryHandle(RelativeTo
,
168 if (!NT_SUCCESS(Status
))
173 return(STATUS_SUCCESS
);
181 RtlDeleteRegistryValue(IN ULONG RelativeTo
,
189 Status
= RtlpGetRegistryHandle(RelativeTo
,
193 if (!NT_SUCCESS(Status
))
196 RtlInitUnicodeString(&Name
,
199 NtDeleteValueKey(KeyHandle
,
204 return(STATUS_SUCCESS
);
212 RtlFormatCurrentUserKeyPath(IN OUT PUNICODE_STRING KeyPath
)
215 RtlCreateUnicodeString(KeyPath
,
216 L
"\\Registry\\User\\.Default");
218 return(STATUS_SUCCESS
);
223 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess
,
224 OUT PHANDLE KeyHandle
)
226 OBJECT_ATTRIBUTES ObjectAttributes
;
227 UNICODE_STRING KeyPath
= ROS_STRING_INITIALIZER(L
"\\Registry\\User\\.Default");
230 Status
= RtlFormatCurrentUserKeyPath(&KeyPath
);
231 if (NT_SUCCESS(Status
))
233 InitializeObjectAttributes(&ObjectAttributes
,
235 OBJ_CASE_INSENSITIVE
,
238 Status
= NtOpenKey(KeyHandle
,
241 RtlFreeUnicodeString(&KeyPath
);
242 if (NT_SUCCESS(Status
))
243 return(STATUS_SUCCESS
);
246 InitializeObjectAttributes(&ObjectAttributes
,
248 OBJ_CASE_INSENSITIVE
,
251 Status
= NtOpenKey(KeyHandle
,
262 RtlQueryRegistryValues(IN ULONG RelativeTo
,
264 IN PRTL_QUERY_REGISTRY_TABLE QueryTable
,
266 IN PVOID Environment
)
269 HANDLE BaseKeyHandle
;
270 HANDLE CurrentKeyHandle
;
271 PRTL_QUERY_REGISTRY_TABLE QueryEntry
;
272 OBJECT_ATTRIBUTES ObjectAttributes
;
273 UNICODE_STRING KeyName
;
274 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
275 PKEY_VALUE_FULL_INFORMATION FullValueInfo
;
284 DPRINT("RtlQueryRegistryValues() called\n");
286 Status
= RtlpGetRegistryHandle(RelativeTo
,
290 if (!NT_SUCCESS(Status
))
292 DPRINT("RtlpGetRegistryHandle() failed with status %x\n", Status
);
296 CurrentKeyHandle
= BaseKeyHandle
;
297 QueryEntry
= QueryTable
;
298 while ((QueryEntry
->QueryRoutine
!= NULL
) ||
299 (QueryEntry
->Name
!= NULL
))
301 if (((QueryEntry
->Flags
& (RTL_QUERY_REGISTRY_SUBKEY
| RTL_QUERY_REGISTRY_TOPKEY
)) != 0) &&
302 (BaseKeyHandle
!= CurrentKeyHandle
))
304 NtClose(CurrentKeyHandle
);
305 CurrentKeyHandle
= BaseKeyHandle
;
308 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
)
310 DPRINT("Open new subkey: %S\n", QueryEntry
->Name
);
312 RtlInitUnicodeString(&KeyName
,
314 InitializeObjectAttributes(&ObjectAttributes
,
316 OBJ_CASE_INSENSITIVE
,
319 Status
= NtOpenKey(&CurrentKeyHandle
,
322 if (!NT_SUCCESS(Status
))
325 else if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
327 DPRINT("Query value directly: %S\n", QueryEntry
->Name
);
329 RtlInitUnicodeString(&KeyName
,
332 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
333 ValueInfo
= ExAllocatePool(PagedPool
, BufferSize
);
334 if (ValueInfo
== NULL
)
336 Status
= STATUS_NO_MEMORY
;
340 Status
= ZwQueryValueKey(CurrentKeyHandle
,
342 KeyValuePartialInformation
,
346 if (!NT_SUCCESS(Status
))
348 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
350 ExFreePool(ValueInfo
);
351 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
355 if (QueryEntry
->DefaultType
== REG_SZ
)
357 PUNICODE_STRING ValueString
;
358 PUNICODE_STRING SourceString
;
360 SourceString
= (PUNICODE_STRING
)QueryEntry
->DefaultData
;
361 ValueString
= (PUNICODE_STRING
)QueryEntry
->EntryContext
;
362 if (ValueString
->Buffer
== 0)
364 ValueString
->Length
= SourceString
->Length
;
365 ValueString
->MaximumLength
= SourceString
->MaximumLength
;
366 ValueString
->Buffer
= ExAllocatePool(PagedPool
,
367 ValueString
->MaximumLength
);
368 if (!ValueString
->Buffer
)
370 ValueString
->Buffer
[0] = 0;
371 memcpy(ValueString
->Buffer
,
372 SourceString
->Buffer
,
373 SourceString
->MaximumLength
);
377 ValueString
->Length
= RtlRosMin(SourceString
->Length
,
378 ValueString
->MaximumLength
- sizeof(WCHAR
));
379 memcpy(ValueString
->Buffer
,
380 SourceString
->Buffer
,
381 ValueString
->Length
);
382 ((PWSTR
)ValueString
->Buffer
)[ValueString
->Length
/ sizeof(WCHAR
)] = 0;
387 memcpy(QueryEntry
->EntryContext
,
388 QueryEntry
->DefaultData
,
389 QueryEntry
->DefaultLength
);
391 Status
= STATUS_SUCCESS
;
395 if (ValueInfo
->Type
== REG_SZ
||
396 ValueInfo
->Type
== REG_MULTI_SZ
||
397 ValueInfo
->Type
== REG_EXPAND_SZ
)
399 PUNICODE_STRING ValueString
;
401 ValueString
= (PUNICODE_STRING
)QueryEntry
->EntryContext
;
402 if (ValueString
->Buffer
== 0)
404 RtlInitUnicodeString(ValueString
,
406 ValueString
->MaximumLength
= ValueInfo
->DataLength
;
407 ValueString
->Buffer
= ExAllocatePool(PagedPool
,
408 ValueString
->MaximumLength
);
409 if (!ValueString
->Buffer
)
411 ValueString
->Buffer
[0] = 0;
413 ValueString
->Length
= RtlRosMin(ValueInfo
->DataLength
,
414 ValueString
->MaximumLength
) - sizeof(WCHAR
);
415 memcpy(ValueString
->Buffer
,
417 ValueString
->Length
);
418 ((PWSTR
)ValueString
->Buffer
)[ValueString
->Length
/ sizeof(WCHAR
)] = 0;
422 memcpy(QueryEntry
->EntryContext
,
424 ValueInfo
->DataLength
);
428 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
430 DPRINT("FIXME: Delete value: %S\n", QueryEntry
->Name
);
434 ExFreePool(ValueInfo
);
438 DPRINT("Query value via query routine: %S\n", QueryEntry
->Name
);
440 if (QueryEntry
->Name
!= NULL
)
442 DPRINT("Callback\n");
444 RtlInitUnicodeString(&KeyName
,
447 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
448 ValueInfo
= ExAllocatePool(PagedPool
,
450 if (ValueInfo
== NULL
)
452 Status
= STATUS_NO_MEMORY
;
456 Status
= NtQueryValueKey(CurrentKeyHandle
,
458 KeyValuePartialInformation
,
462 if (!NT_SUCCESS(Status
))
464 if (! (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
))
466 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
467 QueryEntry
->DefaultType
,
468 QueryEntry
->DefaultData
,
469 QueryEntry
->DefaultLength
,
471 QueryEntry
->EntryContext
);
474 else if ((ValueInfo
->Type
== REG_MULTI_SZ
) &&
475 !(QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
477 DPRINT("Expand REG_MULTI_SZ type\n");
478 StringPtr
= (PWSTR
)ValueInfo
->Data
;
479 while (*StringPtr
!= 0)
481 StringLen
= (wcslen(StringPtr
) + 1) * sizeof(WCHAR
);
482 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
487 QueryEntry
->EntryContext
);
488 if(!NT_SUCCESS(Status
))
490 StringPtr
= (PWSTR
)((PUCHAR
)StringPtr
+ StringLen
);
495 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
498 ValueInfo
->DataLength
,
500 QueryEntry
->EntryContext
);
503 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
505 DPRINT("FIXME: Delete value: %S\n", QueryEntry
->Name
);
509 ExFreePool(ValueInfo
);
511 if (!NT_SUCCESS(Status
))
514 else if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOVALUE
)
516 DPRINT("Simple callback\n");
517 Status
= QueryEntry
->QueryRoutine(NULL
,
522 QueryEntry
->EntryContext
);
523 if (!NT_SUCCESS(Status
))
528 DPRINT("Enumerate values\n");
530 BufferSize
= sizeof(KEY_VALUE_FULL_INFORMATION
) + 4096;
531 FullValueInfo
= ExAllocatePool(PagedPool
,
533 if (FullValueInfo
== NULL
)
535 Status
= STATUS_NO_MEMORY
;
538 ValueNameSize
= 256 * sizeof(WCHAR
);
539 ValueName
= ExAllocatePool(PagedPool
,
541 if (ValueName
== NULL
)
543 Status
= STATUS_NO_MEMORY
;
549 Status
= NtEnumerateValueKey(CurrentKeyHandle
,
551 KeyValueFullInformation
,
555 if (!NT_SUCCESS(Status
))
557 if ((Status
== STATUS_NO_MORE_ENTRIES
) &&
559 (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
))
561 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
563 else if (Status
== STATUS_NO_MORE_ENTRIES
)
565 Status
= STATUS_SUCCESS
;
570 if (FullValueInfo
->NameLength
> ValueNameSize
- sizeof(WCHAR
))
572 /* Should not happen, because the name length is limited to 255 characters */
573 ExFreePool(ValueName
);
574 ValueNameSize
= FullValueInfo
->NameLength
+ sizeof(WCHAR
);
575 ValueName
= ExAllocatePool(PagedPool
, ValueNameSize
);
576 if (ValueName
== NULL
)
578 Status
= STATUS_NO_MEMORY
;
583 RtlCopyMemory(ValueName
,
585 FullValueInfo
->NameLength
);
586 ValueName
[FullValueInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
588 if ((FullValueInfo
->Type
== REG_MULTI_SZ
) &&
589 !(QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
591 DPRINT("Expand REG_MULTI_SZ type\n");
593 StringPtr
= (PWSTR
)((char*)FullValueInfo
+ FullValueInfo
->DataOffset
);
594 while (*StringPtr
!= 0)
596 StringLen
= (wcslen(StringPtr
) + 1) * sizeof(WCHAR
);
597 Status
= QueryEntry
->QueryRoutine(ValueName
,
602 QueryEntry
->EntryContext
);
603 if(!NT_SUCCESS(Status
))
605 StringPtr
= (PWSTR
)((PUCHAR
)StringPtr
+ StringLen
);
610 Status
= QueryEntry
->QueryRoutine(ValueName
,
612 (char*)FullValueInfo
+ FullValueInfo
->DataOffset
,
613 FullValueInfo
->DataLength
,
615 QueryEntry
->EntryContext
);
618 if (!NT_SUCCESS(Status
))
621 /* FIXME: How will these be deleted? */
626 ExFreePool(FullValueInfo
);
627 ExFreePool(ValueName
);
629 if (!NT_SUCCESS(Status
))
639 if (CurrentKeyHandle
!= BaseKeyHandle
)
640 NtClose(CurrentKeyHandle
);
642 NtClose(BaseKeyHandle
);
652 RtlWriteRegistryValue(IN ULONG RelativeTo
,
657 IN ULONG ValueLength
)
663 Status
= RtlpGetRegistryHandle(RelativeTo
,
667 if (!NT_SUCCESS(Status
))
670 RtlInitUnicodeString(&Name
,
673 NtSetValueKey(KeyHandle
,
682 return(STATUS_SUCCESS
);