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>
13 #include <internal/ob.h>
16 #include <internal/registry.h>
19 #include <internal/debug.h>
24 /* FUNCTIONS ****************************************************************/
30 RtlCheckRegistryKey(IN ULONG RelativeTo,
36 Status = RtlpGetRegistryHandle(RelativeTo,
40 if (!NT_SUCCESS(Status))
45 return(STATUS_SUCCESS);
53 RtlCreateRegistryKey(IN ULONG RelativeTo,
59 Status = RtlpGetRegistryHandle(RelativeTo,
63 if (!NT_SUCCESS(Status))
68 return(STATUS_SUCCESS);
76 RtlDeleteRegistryValue(IN ULONG RelativeTo,
84 Status = RtlpGetRegistryHandle(RelativeTo,
88 if (!NT_SUCCESS(Status))
91 RtlInitUnicodeString(&Name,
94 NtDeleteValueKey(KeyHandle,
99 return(STATUS_SUCCESS);
104 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
105 OUT PHANDLE KeyHandle)
107 OBJECT_ATTRIBUTES ObjectAttributes;
108 UNICODE_STRING KeyPath = UNICODE_STRING_INITIALIZER(L"\\Registry\\User\\.Default");
111 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
112 if (NT_SUCCESS(Status))
114 InitializeObjectAttributes(&ObjectAttributes,
116 OBJ_CASE_INSENSITIVE,
119 Status = NtOpenKey(KeyHandle,
122 RtlFreeUnicodeString(&KeyPath);
123 if (NT_SUCCESS(Status))
124 return(STATUS_SUCCESS);
127 InitializeObjectAttributes(&ObjectAttributes,
129 OBJ_CASE_INSENSITIVE,
132 Status = NtOpenKey(KeyHandle,
143 RtlQueryRegistryValues(IN ULONG RelativeTo,
145 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
147 IN PVOID Environment)
150 HANDLE BaseKeyHandle;
151 HANDLE CurrentKeyHandle;
152 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
153 OBJECT_ATTRIBUTES ObjectAttributes;
154 UNICODE_STRING KeyName;
155 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
156 PKEY_VALUE_FULL_INFORMATION FullValueInfo;
165 DPRINT("RtlQueryRegistryValues() called\n");
167 Status = RtlpGetRegistryHandle(RelativeTo,
171 if (!NT_SUCCESS(Status))
173 DPRINT("RtlpGetRegistryHandle() failed with status %x\n", Status);
177 CurrentKeyHandle = BaseKeyHandle;
178 QueryEntry = QueryTable;
179 while ((QueryEntry->QueryRoutine != NULL) ||
180 (QueryEntry->Name != NULL))
182 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
183 (BaseKeyHandle != CurrentKeyHandle))
185 NtClose(CurrentKeyHandle);
186 CurrentKeyHandle = BaseKeyHandle;
189 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
191 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
193 RtlInitUnicodeString(&KeyName,
195 InitializeObjectAttributes(&ObjectAttributes,
197 OBJ_CASE_INSENSITIVE,
200 Status = NtOpenKey(&CurrentKeyHandle,
203 if (!NT_SUCCESS(Status))
206 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
208 DPRINT("Query value directly: %S\n", QueryEntry->Name);
210 RtlInitUnicodeString(&KeyName,
213 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
214 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
215 if (ValueInfo == NULL)
217 Status = STATUS_NO_MEMORY;
221 Status = ZwQueryValueKey(CurrentKeyHandle,
223 KeyValuePartialInformation,
227 if (!NT_SUCCESS(Status))
229 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
231 ExFreePool(ValueInfo);
232 Status = STATUS_OBJECT_NAME_NOT_FOUND;
236 if (QueryEntry->DefaultType == REG_SZ)
238 PUNICODE_STRING ValueString;
239 PUNICODE_STRING SourceString;
241 SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
242 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
243 if (ValueString->Buffer == 0)
245 ValueString->Length = SourceString->Length;
246 ValueString->MaximumLength = SourceString->MaximumLength;
247 ValueString->Buffer = ExAllocatePool(PagedPool,
248 ValueString->MaximumLength);
249 if (!ValueString->Buffer)
251 ValueString->Buffer[0] = 0;
252 memcpy(ValueString->Buffer,
253 SourceString->Buffer,
254 SourceString->MaximumLength);
258 ValueString->Length = RtlMin(SourceString->Length,
259 ValueString->MaximumLength - sizeof(WCHAR));
260 memcpy(ValueString->Buffer,
261 SourceString->Buffer,
262 ValueString->Length);
263 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
268 memcpy(QueryEntry->EntryContext,
269 QueryEntry->DefaultData,
270 QueryEntry->DefaultLength);
272 Status = STATUS_SUCCESS;
276 if (ValueInfo->Type == REG_SZ ||
277 ValueInfo->Type == REG_MULTI_SZ ||
278 ValueInfo->Type == REG_EXPAND_SZ)
280 PUNICODE_STRING ValueString;
282 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
283 if (ValueString->Buffer == 0)
285 RtlInitUnicodeString(ValueString,
287 ValueString->MaximumLength = ValueInfo->DataLength;
288 ValueString->Buffer = ExAllocatePool(PagedPool,
289 ValueString->MaximumLength);
290 if (!ValueString->Buffer)
292 ValueString->Buffer[0] = 0;
294 ValueString->Length = RtlMin(ValueInfo->DataLength,
295 ValueString->MaximumLength) - sizeof(WCHAR);
296 memcpy(ValueString->Buffer,
298 ValueString->Length);
299 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
303 memcpy(QueryEntry->EntryContext,
305 ValueInfo->DataLength);
309 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
311 DPRINT("FIXME: Delete value: %S\n", QueryEntry->Name);
315 ExFreePool(ValueInfo);
319 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
321 if (QueryEntry->Name != NULL)
323 DPRINT("Callback\n");
325 RtlInitUnicodeString(&KeyName,
328 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
329 ValueInfo = ExAllocatePool(PagedPool,
331 if (ValueInfo == NULL)
333 Status = STATUS_NO_MEMORY;
337 Status = NtQueryValueKey(CurrentKeyHandle,
339 KeyValuePartialInformation,
343 if (!NT_SUCCESS(Status))
345 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
346 QueryEntry->DefaultType,
347 QueryEntry->DefaultData,
348 QueryEntry->DefaultLength,
350 QueryEntry->EntryContext);
352 else if ((ValueInfo->Type == REG_MULTI_SZ) &&
353 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
355 DPRINT("Expand REG_MULTI_SZ type\n");
356 StringPtr = (PWSTR)ValueInfo->Data;
357 while (*StringPtr != 0)
359 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
360 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
365 QueryEntry->EntryContext);
366 if(!NT_SUCCESS(Status))
368 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
373 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
376 ValueInfo->DataLength,
378 QueryEntry->EntryContext);
381 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
383 DPRINT("FIXME: Delete value: %S\n", QueryEntry->Name);
387 ExFreePool(ValueInfo);
389 if (!NT_SUCCESS(Status))
392 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
394 DPRINT("Simple callback\n");
395 Status = QueryEntry->QueryRoutine(NULL,
400 QueryEntry->EntryContext);
401 if (!NT_SUCCESS(Status))
406 DPRINT("Enumerate values\n");
408 BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
409 FullValueInfo = ExAllocatePool(PagedPool,
411 if (FullValueInfo == NULL)
413 Status = STATUS_NO_MEMORY;
416 ValueNameSize = 256 * sizeof(WCHAR);
417 ValueName = ExAllocatePool(PagedPool,
419 if (ValueName == NULL)
421 Status = STATUS_NO_MEMORY;
427 Status = NtEnumerateValueKey(CurrentKeyHandle,
429 KeyValueFullInformation,
433 if (!NT_SUCCESS(Status))
435 if ((Status == STATUS_NO_MORE_ENTRIES) &&
437 (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
439 Status = STATUS_OBJECT_NAME_NOT_FOUND;
441 else if (Status == STATUS_NO_MORE_ENTRIES)
443 Status = STATUS_SUCCESS;
448 if (FullValueInfo->NameLength > ValueNameSize - sizeof(WCHAR))
450 /* Should not happen, because the name length is limited to 255 characters */
451 ExFreePool(ValueName);
452 ValueNameSize = FullValueInfo->NameLength + sizeof(WCHAR);
453 ValueName = ExAllocatePool(PagedPool, ValueNameSize);
454 if (ValueName == NULL)
456 Status = STATUS_NO_MEMORY;
461 RtlCopyMemory(ValueName,
463 FullValueInfo->NameLength);
464 ValueName[FullValueInfo->NameLength / sizeof(WCHAR)] = 0;
466 if ((FullValueInfo->Type == REG_MULTI_SZ) &&
467 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
469 DPRINT("Expand REG_MULTI_SZ type\n");
471 StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
472 while (*StringPtr != 0)
474 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
475 Status = QueryEntry->QueryRoutine(ValueName,
480 QueryEntry->EntryContext);
481 if(!NT_SUCCESS(Status))
483 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
488 Status = QueryEntry->QueryRoutine(ValueName,
490 (PVOID)FullValueInfo + FullValueInfo->DataOffset,
491 FullValueInfo->DataLength,
493 QueryEntry->EntryContext);
496 if (!NT_SUCCESS(Status))
499 /* FIXME: How will these be deleted? */
504 ExFreePool(FullValueInfo);
505 ExFreePool(ValueName);
507 if (!NT_SUCCESS(Status))
517 if (CurrentKeyHandle != BaseKeyHandle)
518 NtClose(CurrentKeyHandle);
520 NtClose(BaseKeyHandle);
530 RtlWriteRegistryValue(IN ULONG RelativeTo,
535 IN ULONG ValueLength)
541 Status = RtlpGetRegistryHandle(RelativeTo,
545 if (!NT_SUCCESS(Status))
548 RtlInitUnicodeString(&Name,
551 NtSetValueKey(KeyHandle,
560 return(STATUS_SUCCESS);
568 RtlFormatCurrentUserKeyPath(IN OUT PUNICODE_STRING KeyPath)
571 RtlCreateUnicodeString(KeyPath,
572 L"\\Registry\\User\\.Default");
574 return(STATUS_SUCCESS);
577 /* ------------------------------------------ Private Implementation */
581 RtlpGetRegistryHandle(ULONG RelativeTo,
586 UNICODE_STRING KeyName;
587 WCHAR KeyBuffer[MAX_PATH];
588 OBJECT_ATTRIBUTES ObjectAttributes;
591 if (RelativeTo & RTL_REGISTRY_HANDLE)
593 Status = NtDuplicateObject(PsGetCurrentProcessId(),
595 PsGetCurrentProcessId(),
599 DUPLICATE_SAME_ACCESS);
603 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
604 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
606 if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
607 return STATUS_INVALID_PARAMETER;
610 KeyName.MaximumLength = MAX_PATH;
611 KeyName.Buffer = KeyBuffer;
616 case RTL_REGISTRY_SERVICES:
617 RtlAppendUnicodeToString(&KeyName,
618 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
621 case RTL_REGISTRY_CONTROL:
622 RtlAppendUnicodeToString(&KeyName,
623 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
626 case RTL_REGISTRY_WINDOWS_NT:
627 RtlAppendUnicodeToString(&KeyName,
628 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
631 case RTL_REGISTRY_DEVICEMAP:
632 RtlAppendUnicodeToString(&KeyName,
633 L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
636 case RTL_REGISTRY_USER:
637 Status = RtlFormatCurrentUserKeyPath(&KeyName);
638 if (!NT_SUCCESS(Status))
642 /* ReactOS specific */
643 case RTL_REGISTRY_ENUM:
644 RtlAppendUnicodeToString(&KeyName,
645 L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
649 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
653 RtlAppendUnicodeToString(&KeyName,
656 DPRINT("KeyName '%wZ'\n", &KeyName);
658 InitializeObjectAttributes(&ObjectAttributes,
660 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
666 Status = NtCreateKey(KeyHandle,
676 Status = NtOpenKey(KeyHandle,
686 RtlpCreateRegistryKeyPath(PWSTR Path)
688 OBJECT_ATTRIBUTES ObjectAttributes;
689 WCHAR KeyBuffer[MAX_PATH];
690 UNICODE_STRING KeyName;
696 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
698 return STATUS_INVALID_PARAMETER;
701 wcsncpy (KeyBuffer, Path, MAX_PATH-1);
702 RtlInitUnicodeString (&KeyName, KeyBuffer);
704 /* Skip \\Registry\\ */
705 Current = KeyName.Buffer;
706 Current = wcschr (Current, '\\') + 1;
707 Current = wcschr (Current, '\\') + 1;
711 Next = wcschr (Current, '\\');
721 InitializeObjectAttributes (&ObjectAttributes,
723 OBJ_CASE_INSENSITIVE,
727 DPRINT("Create '%S'\n", KeyName.Buffer);
729 Status = NtCreateKey (&KeyHandle,
736 if (!NT_SUCCESS (Status))
738 DPRINT ("NtCreateKey() failed with status %x\n", Status);
751 while (Next != NULL);
753 return STATUS_SUCCESS;