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 *****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
19 #include <internal/pool.h>
20 #include <internal/registry.h>
23 #include <internal/debug.h>
29 /* FUNCTIONS ****************************************************************/
32 RtlCheckRegistryKey(IN ULONG RelativeTo,
38 Status = RtlpGetRegistryHandle(RelativeTo,
42 if (!NT_SUCCESS(Status))
47 return(STATUS_SUCCESS);
52 RtlCreateRegistryKey(IN ULONG RelativeTo,
58 Status = RtlpGetRegistryHandle(RelativeTo,
62 if (!NT_SUCCESS(Status))
67 return(STATUS_SUCCESS);
72 RtlDeleteRegistryValue(IN ULONG RelativeTo,
80 Status = RtlpGetRegistryHandle(RelativeTo,
84 if (!NT_SUCCESS(Status))
87 RtlInitUnicodeString(&Name,
90 NtDeleteValueKey(KeyHandle,
95 return(STATUS_SUCCESS);
100 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess,
101 OUT PHANDLE KeyHandle)
103 OBJECT_ATTRIBUTES ObjectAttributes;
104 UNICODE_STRING KeyPath = UNICODE_STRING_INITIALIZER(L"\\Registry\\User\\.Default");
107 Status = RtlFormatCurrentUserKeyPath(&KeyPath);
108 if (NT_SUCCESS(Status))
110 InitializeObjectAttributes(&ObjectAttributes,
112 OBJ_CASE_INSENSITIVE,
115 Status = NtOpenKey(KeyHandle,
118 RtlFreeUnicodeString(&KeyPath);
119 if (NT_SUCCESS(Status))
120 return(STATUS_SUCCESS);
123 InitializeObjectAttributes(&ObjectAttributes,
125 OBJ_CASE_INSENSITIVE,
128 Status = NtOpenKey(KeyHandle,
136 RtlQueryRegistryValues(IN ULONG RelativeTo,
138 IN PRTL_QUERY_REGISTRY_TABLE QueryTable,
140 IN PVOID Environment)
143 HANDLE BaseKeyHandle;
144 HANDLE CurrentKeyHandle;
145 PRTL_QUERY_REGISTRY_TABLE QueryEntry;
146 OBJECT_ATTRIBUTES ObjectAttributes;
147 UNICODE_STRING KeyName;
148 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
149 PKEY_VALUE_FULL_INFORMATION FullValueInfo;
156 DPRINT("RtlQueryRegistryValues() called\n");
158 BaseKeyHandle = NULL;
159 CurrentKeyHandle = NULL;
162 Status = RtlpGetRegistryHandle(RelativeTo,
166 if (!NT_SUCCESS(Status))
168 DPRINT("RtlpGetRegistryHandle() failed with status %x\n", Status);
172 CurrentKeyHandle = BaseKeyHandle;
173 QueryEntry = QueryTable;
174 while ((QueryEntry->QueryRoutine != NULL) ||
175 (QueryEntry->Name != NULL))
179 packet.sys has this code which calls this (and fails here) with:
181 RtlZeroMemory(ParamTable, sizeof(ParamTable));
183 // change to the linkage key
185 ParamTable[0].QueryRoutine = NULL; // NOTE: QueryRoutine is set to NULL
186 ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
187 ParamTable[0].Name = L"Linkage";
189 // Get the name of the mac driver we should bind to
191 ParamTable[1].QueryRoutine = PacketQueryRegistryRoutine;
192 ParamTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
193 ParamTable[1].Name = L"Bind";
194 ParamTable[1].EntryContext = (PVOID)MacDriverName;
195 ParamTable[1].DefaultType = REG_MULTI_SZ;
197 Status = RtlQueryRegistryValues(
198 IN ULONG RelativeTo = RTL_REGISTRY_ABSOLUTE,
199 IN PWSTR Path = Path,
200 IN PRTL_QUERY_REGISTRY_TABLE QueryTable = ParamTable,
201 IN PVOID Context = NULL,
202 IN PVOID Environment = NULL);
206 //if ((QueryEntry->QueryRoutine == NULL) &&
207 // ((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_DIRECT)) != 0))
208 // Which is more correct?
209 if ((QueryEntry->QueryRoutine == NULL) &&
210 ((QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY) != 0))
212 DPRINT("Bad parameters\n");
213 Status = STATUS_INVALID_PARAMETER;
217 DPRINT("Name: %S\n", QueryEntry->Name);
219 if (((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_TOPKEY)) != 0) &&
220 (BaseKeyHandle != CurrentKeyHandle))
222 NtClose(CurrentKeyHandle);
223 CurrentKeyHandle = BaseKeyHandle;
226 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_SUBKEY)
228 DPRINT("Open new subkey: %S\n", QueryEntry->Name);
230 RtlInitUnicodeString(&KeyName,
232 InitializeObjectAttributes(&ObjectAttributes,
234 OBJ_CASE_INSENSITIVE,
237 Status = NtOpenKey(&CurrentKeyHandle,
240 if (!NT_SUCCESS(Status))
243 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DIRECT)
245 DPRINT("Query value directly: %S\n", QueryEntry->Name);
247 RtlInitUnicodeString(&KeyName,
250 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
251 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
252 if (ValueInfo == NULL)
254 Status = STATUS_NO_MEMORY;
258 memset(ValueInfo, 0, BufferSize);
260 Status = ZwQueryValueKey(CurrentKeyHandle,
262 KeyValuePartialInformation,
266 if (!NT_SUCCESS(Status))
268 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED)
270 ExFreePool(ValueInfo);
271 Status = STATUS_OBJECT_NAME_NOT_FOUND;
275 if (QueryEntry->DefaultType == REG_SZ)
277 PUNICODE_STRING ValueString;
278 PUNICODE_STRING SourceString;
280 SourceString = (PUNICODE_STRING)QueryEntry->DefaultData;
281 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
282 if (ValueString->Buffer == 0)
284 ValueString->Length = SourceString->Length;
285 ValueString->MaximumLength = SourceString->MaximumLength;
286 ValueString->Buffer = ExAllocatePool(PagedPool,
287 ValueString->MaximumLength);
288 if (!ValueString->Buffer)
290 ValueString->Buffer[0] = 0;
291 memcpy(ValueString->Buffer,
292 SourceString->Buffer,
293 SourceString->MaximumLength);
297 ValueString->Length = RtlMin(SourceString->Length,
298 ValueString->MaximumLength - sizeof(WCHAR));
299 memcpy(ValueString->Buffer,
300 SourceString->Buffer,
301 ValueString->Length);
302 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
307 memcpy(QueryEntry->EntryContext,
308 QueryEntry->DefaultData,
309 QueryEntry->DefaultLength);
311 Status = STATUS_SUCCESS;
315 if (ValueInfo->Type == REG_SZ ||
316 ValueInfo->Type == REG_MULTI_SZ ||
317 ValueInfo->Type == REG_EXPAND_SZ)
319 PUNICODE_STRING ValueString;
321 ValueString = (PUNICODE_STRING)QueryEntry->EntryContext;
322 if (ValueString->Buffer == 0)
324 RtlInitUnicodeString(ValueString,
326 ValueString->MaximumLength = ValueInfo->DataLength + sizeof(WCHAR); //256 * sizeof(WCHAR);
327 ValueString->Buffer = ExAllocatePool(PagedPool,
328 ValueString->MaximumLength);
329 if (!ValueString->Buffer)
331 ValueString->Buffer[0] = 0;
333 ValueString->Length = RtlMin(ValueInfo->DataLength,
334 ValueString->MaximumLength - sizeof(WCHAR));
335 memcpy(ValueString->Buffer,
337 ValueString->Length);
338 ((PWSTR)ValueString->Buffer)[ValueString->Length / sizeof(WCHAR)] = 0;
342 memcpy(QueryEntry->EntryContext,
344 ValueInfo->DataLength);
348 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
350 DPRINT("FIXME: Delete value: %S\n", QueryEntry->Name);
354 ExFreePool(ValueInfo);
358 DPRINT("Query value via query routine: %S\n", QueryEntry->Name);
360 if (QueryEntry->Name != NULL)
362 DPRINT("Callback\n");
364 RtlInitUnicodeString(&KeyName,
367 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
368 ValueInfo = ExAllocatePool(PagedPool,
370 if (ValueInfo == NULL)
372 Status = STATUS_NO_MEMORY;
376 Status = NtQueryValueKey(CurrentKeyHandle,
378 KeyValuePartialInformation,
382 if (!NT_SUCCESS(Status))
384 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
385 QueryEntry->DefaultType,
386 QueryEntry->DefaultData,
387 QueryEntry->DefaultLength,
389 QueryEntry->EntryContext);
391 else if ((ValueInfo->Type == REG_MULTI_SZ) &&
392 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
394 DPRINT("Expand REG_MULTI_SZ type\n");
395 StringPtr = (PWSTR)ValueInfo->Data;
396 while (*StringPtr != 0)
398 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
399 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
404 QueryEntry->EntryContext);
405 if(!NT_SUCCESS(Status))
407 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
412 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
415 ValueInfo->DataLength,
417 QueryEntry->EntryContext);
420 if (QueryEntry->Flags & RTL_QUERY_REGISTRY_DELETE)
422 DPRINT("FIXME: Delete value: %S\n", QueryEntry->Name);
426 ExFreePool(ValueInfo);
428 if (!NT_SUCCESS(Status))
431 else if (QueryEntry->Flags & RTL_QUERY_REGISTRY_NOVALUE)
433 DPRINT("Simple callback\n");
434 Status = QueryEntry->QueryRoutine(NULL,
439 QueryEntry->EntryContext);
440 if (!NT_SUCCESS(Status))
445 DPRINT("Enumerate values\n");
447 BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + 4096;
448 FullValueInfo = ExAllocatePool(PagedPool,
450 if (FullValueInfo == NULL)
452 Status = STATUS_NO_MEMORY;
459 Status = NtEnumerateValueKey(CurrentKeyHandle,
461 KeyValueFullInformation,
465 if (!NT_SUCCESS(Status))
467 if ((Status == STATUS_NO_MORE_ENTRIES) &&
469 (QueryEntry->Flags & RTL_QUERY_REGISTRY_REQUIRED))
471 Status = STATUS_OBJECT_NAME_NOT_FOUND;
473 else if (Status == STATUS_NO_MORE_ENTRIES)
475 Status = STATUS_SUCCESS;
480 if ((FullValueInfo->Type == REG_MULTI_SZ) &&
481 !(QueryEntry->Flags & RTL_QUERY_REGISTRY_NOEXPAND))
483 DPRINT("Expand REG_MULTI_SZ type\n");
485 StringPtr = (PWSTR)(FullValueInfo + FullValueInfo->DataOffset);
487 StringPtr = (PWSTR)((PVOID)FullValueInfo + FullValueInfo->DataOffset);
489 while (*StringPtr != 0)
491 StringLen = (wcslen(StringPtr) + 1) * sizeof(WCHAR);
492 Status = QueryEntry->QueryRoutine(QueryEntry->Name,
497 QueryEntry->EntryContext);
498 if(!NT_SUCCESS(Status))
500 StringPtr = (PWSTR)((PUCHAR)StringPtr + StringLen);
505 Status = QueryEntry->QueryRoutine(FullValueInfo->Name,
508 FullValueInfo + FullValueInfo->DataOffset,
510 (PVOID)FullValueInfo + FullValueInfo->DataOffset,
512 FullValueInfo->DataLength,
514 QueryEntry->EntryContext);
517 if (!NT_SUCCESS(Status))
520 /* FIXME: How will these be deleted? */
525 ExFreePool(FullValueInfo);
527 if (!NT_SUCCESS(Status))
537 if (CurrentKeyHandle != BaseKeyHandle)
538 NtClose(CurrentKeyHandle);
540 NtClose(BaseKeyHandle);
547 RtlWriteRegistryValue(IN ULONG RelativeTo,
552 IN ULONG ValueLength)
558 Status = RtlpGetRegistryHandle(RelativeTo,
562 if (!NT_SUCCESS(Status))
565 RtlInitUnicodeString(&Name,
568 NtSetValueKey(KeyHandle,
577 return(STATUS_SUCCESS);
582 RtlFormatCurrentUserKeyPath(IN OUT PUNICODE_STRING KeyPath)
585 RtlCreateUnicodeString(KeyPath,
586 L"\\Registry\\User\\.Default");
588 return(STATUS_SUCCESS);
591 /* ------------------------------------------ Private Implementation */
595 RtlpGetRegistryHandle(ULONG RelativeTo,
600 UNICODE_STRING KeyName;
601 WCHAR KeyBuffer[MAX_PATH];
602 OBJECT_ATTRIBUTES ObjectAttributes;
605 if (RelativeTo & RTL_REGISTRY_HANDLE)
607 Status = NtDuplicateObject(PsGetCurrentProcessId(),
609 PsGetCurrentProcessId(),
613 DUPLICATE_SAME_ACCESS);
617 if (RelativeTo & RTL_REGISTRY_OPTIONAL)
618 RelativeTo &= ~RTL_REGISTRY_OPTIONAL;
620 if (RelativeTo >= RTL_REGISTRY_MAXIMUM)
621 return STATUS_INVALID_PARAMETER;
624 KeyName.MaximumLength = MAX_PATH;
625 KeyName.Buffer = KeyBuffer;
630 case RTL_REGISTRY_SERVICES:
631 RtlAppendUnicodeToString(&KeyName,
632 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
635 case RTL_REGISTRY_CONTROL:
636 RtlAppendUnicodeToString(&KeyName,
637 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
640 case RTL_REGISTRY_WINDOWS_NT:
641 RtlAppendUnicodeToString(&KeyName,
642 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
645 case RTL_REGISTRY_DEVICEMAP:
646 RtlAppendUnicodeToString(&KeyName,
647 L"\\Registry\\Machine\\Hardware\\DeviceMap\\");
650 case RTL_REGISTRY_USER:
651 Status = RtlFormatCurrentUserKeyPath(&KeyName);
652 if (!NT_SUCCESS(Status))
656 /* ReactOS specific */
657 case RTL_REGISTRY_ENUM:
658 RtlAppendUnicodeToString(&KeyName,
659 L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
663 if (Path[0] == L'\\' && RelativeTo != RTL_REGISTRY_ABSOLUTE)
667 RtlAppendUnicodeToString(&KeyName,
670 DPRINT("KeyName '%wZ'\n", &KeyName);
672 InitializeObjectAttributes(&ObjectAttributes,
674 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
680 Status = NtCreateKey(KeyHandle,
690 Status = NtOpenKey(KeyHandle,
700 RtlpCreateRegistryKeyPath(PWSTR Path)
702 OBJECT_ATTRIBUTES ObjectAttributes;
703 WCHAR KeyBuffer[MAX_PATH];
704 UNICODE_STRING KeyName;
710 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
712 return(STATUS_INVALID_PARAMETER);
715 wcsncpy(KeyBuffer, Path, MAX_PATH-1);
716 RtlInitUnicodeString(&KeyName, KeyBuffer);
718 /* Skip \\Registry\\ */
719 Current = KeyName.Buffer;
720 Current = wcschr(Current, '\\') + 1;
721 Current = wcschr(Current, '\\') + 1;
724 Next = wcschr(Current, '\\');
734 InitializeObjectAttributes(
737 OBJ_CASE_INSENSITIVE,
741 DPRINT("Create '%S'\n", KeyName.Buffer);
743 Status = NtCreateKey(
751 if (!NT_SUCCESS(Status))
753 DPRINT("NtCreateKey() failed with status %x\n", Status);
765 } while (Next != NULL);
767 return STATUS_SUCCESS;