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
11 #include <internal/ob.h>
14 #include <internal/pool.h>
15 #include <internal/registry.h>
18 #include <internal/debug.h>
23 RtlCheckRegistryKey(IN ULONG RelativeTo
,
29 Status
= RtlpGetRegistryHandle(RelativeTo
,
33 if (!NT_SUCCESS(Status
))
38 return(STATUS_SUCCESS
);
43 RtlCreateRegistryKey(IN ULONG RelativeTo
,
49 Status
= RtlpGetRegistryHandle(RelativeTo
,
53 if (!NT_SUCCESS(Status
))
58 return(STATUS_SUCCESS
);
63 RtlDeleteRegistryValue(IN ULONG RelativeTo
,
71 Status
= RtlpGetRegistryHandle(RelativeTo
,
75 if (!NT_SUCCESS(Status
))
78 RtlInitUnicodeString(&Name
,
81 NtDeleteValueKey(KeyHandle
,
86 return(STATUS_SUCCESS
);
91 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess
,
92 OUT PHANDLE KeyHandle
)
94 OBJECT_ATTRIBUTES ObjectAttributes
;
95 UNICODE_STRING KeyPath
= UNICODE_STRING_INITIALIZER(L
"\\Registry\\User\\.Default");
98 Status
= RtlFormatCurrentUserKeyPath(&KeyPath
);
99 if (NT_SUCCESS(Status
))
101 InitializeObjectAttributes(&ObjectAttributes
,
103 OBJ_CASE_INSENSITIVE
,
106 Status
= NtOpenKey(KeyHandle
,
109 RtlFreeUnicodeString(&KeyPath
);
110 if (NT_SUCCESS(Status
))
111 return(STATUS_SUCCESS
);
114 InitializeObjectAttributes(&ObjectAttributes
,
116 OBJ_CASE_INSENSITIVE
,
119 Status
= NtOpenKey(KeyHandle
,
127 RtlQueryRegistryValues(IN ULONG RelativeTo
,
129 IN PRTL_QUERY_REGISTRY_TABLE QueryTable
,
131 IN PVOID Environment
)
134 HANDLE BaseKeyHandle
;
135 HANDLE CurrentKeyHandle
;
136 PRTL_QUERY_REGISTRY_TABLE QueryEntry
;
137 OBJECT_ATTRIBUTES ObjectAttributes
;
138 UNICODE_STRING KeyName
;
139 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
140 PKEY_VALUE_FULL_INFORMATION FullValueInfo
;
147 DPRINT("RtlQueryRegistryValues() called\n");
149 Status
= RtlpGetRegistryHandle(RelativeTo
,
153 if (!NT_SUCCESS(Status
))
155 DPRINT("RtlpGetRegistryHandle() failed with status %x\n", Status
);
159 CurrentKeyHandle
= BaseKeyHandle
;
160 QueryEntry
= QueryTable
;
161 while ((QueryEntry
->QueryRoutine
!= NULL
) ||
162 (QueryEntry
->Name
!= NULL
))
166 packet.sys has this code which calls this (and fails here) with:
168 RtlZeroMemory(ParamTable, sizeof(ParamTable));
170 // change to the linkage key
172 ParamTable[0].QueryRoutine = NULL; // NOTE: QueryRoutine is set to NULL
173 ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
174 ParamTable[0].Name = L"Linkage";
176 // Get the name of the mac driver we should bind to
178 ParamTable[1].QueryRoutine = PacketQueryRegistryRoutine;
179 ParamTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
180 ParamTable[1].Name = L"Bind";
181 ParamTable[1].EntryContext = (PVOID)MacDriverName;
182 ParamTable[1].DefaultType = REG_MULTI_SZ;
184 Status = RtlQueryRegistryValues(
185 IN ULONG RelativeTo = RTL_REGISTRY_ABSOLUTE,
186 IN PWSTR Path = Path,
187 IN PRTL_QUERY_REGISTRY_TABLE QueryTable = ParamTable,
188 IN PVOID Context = NULL,
189 IN PVOID Environment = NULL);
193 //if ((QueryEntry->QueryRoutine == NULL) &&
194 // ((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_DIRECT)) != 0))
195 // Which is more correct?
196 if ((QueryEntry
->QueryRoutine
== NULL
) &&
197 ((QueryEntry
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
) != 0))
199 DPRINT("Bad parameters\n");
200 Status
= STATUS_INVALID_PARAMETER
;
204 DPRINT("Name: %S\n", QueryEntry
->Name
);
206 if (((QueryEntry
->Flags
& (RTL_QUERY_REGISTRY_SUBKEY
| RTL_QUERY_REGISTRY_TOPKEY
)) != 0) &&
207 (BaseKeyHandle
!= CurrentKeyHandle
))
209 NtClose(CurrentKeyHandle
);
210 CurrentKeyHandle
= BaseKeyHandle
;
213 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
)
215 DPRINT("Open new subkey: %S\n", QueryEntry
->Name
);
217 RtlInitUnicodeString(&KeyName
,
219 InitializeObjectAttributes(&ObjectAttributes
,
221 OBJ_CASE_INSENSITIVE
,
224 Status
= NtOpenKey(&CurrentKeyHandle
,
227 if (!NT_SUCCESS(Status
))
230 else if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
232 DPRINT("Query value directly: %S\n", QueryEntry
->Name
);
234 RtlInitUnicodeString(&KeyName
,
237 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
238 ValueInfo
= ExAllocatePool(PagedPool
, BufferSize
);
239 if (ValueInfo
== NULL
)
241 Status
= STATUS_NO_MEMORY
;
245 Status
= ZwQueryValueKey(CurrentKeyHandle
,
247 KeyValuePartialInformation
,
251 if (!NT_SUCCESS(Status
))
253 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
255 ExFreePool(ValueInfo
);
256 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
260 if (QueryEntry
->DefaultType
== REG_SZ
)
262 PUNICODE_STRING ValueString
;
263 PUNICODE_STRING SourceString
;
265 SourceString
= (PUNICODE_STRING
)QueryEntry
->DefaultData
;
266 ValueString
= (PUNICODE_STRING
)QueryEntry
->EntryContext
;
267 if (ValueString
->Buffer
== 0)
269 ValueString
->Length
= SourceString
->Length
;
270 ValueString
->MaximumLength
= SourceString
->MaximumLength
;
271 ValueString
->Buffer
= ExAllocatePool(PagedPool
,
272 ValueString
->MaximumLength
);
273 if (!ValueString
->Buffer
)
275 ValueString
->Buffer
[0] = 0;
276 memcpy(ValueString
->Buffer
,
277 SourceString
->Buffer
,
278 SourceString
->MaximumLength
);
282 ValueString
->Length
= RtlMin(SourceString
->Length
,
283 ValueString
->MaximumLength
- sizeof(WCHAR
));
284 memcpy(ValueString
->Buffer
,
285 SourceString
->Buffer
,
286 ValueString
->Length
);
287 ((PWSTR
)ValueString
->Buffer
)[ValueString
->Length
/ sizeof(WCHAR
)] = 0;
292 memcpy(QueryEntry
->EntryContext
,
293 QueryEntry
->DefaultData
,
294 QueryEntry
->DefaultLength
);
296 Status
= STATUS_SUCCESS
;
300 if (ValueInfo
->Type
== REG_SZ
||
301 ValueInfo
->Type
== REG_MULTI_SZ
||
302 ValueInfo
->Type
== REG_EXPAND_SZ
)
304 PUNICODE_STRING ValueString
;
306 ValueString
= (PUNICODE_STRING
)QueryEntry
->EntryContext
;
307 if (ValueString
->Buffer
== 0)
309 RtlInitUnicodeString(ValueString
,
311 ValueString
->MaximumLength
= ValueInfo
->DataLength
+ sizeof(WCHAR
); //256 * sizeof(WCHAR);
312 ValueString
->Buffer
= ExAllocatePool(PagedPool
,
313 ValueString
->MaximumLength
);
314 if (!ValueString
->Buffer
)
316 ValueString
->Buffer
[0] = 0;
318 ValueString
->Length
= RtlMin(ValueInfo
->DataLength
,
319 ValueString
->MaximumLength
- sizeof(WCHAR
));
320 memcpy(ValueString
->Buffer
,
322 ValueString
->Length
);
323 ((PWSTR
)ValueString
->Buffer
)[ValueString
->Length
/ sizeof(WCHAR
)] = 0;
327 memcpy(QueryEntry
->EntryContext
,
329 ValueInfo
->DataLength
);
333 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
335 DPRINT("FIXME: Delete value: %S\n", QueryEntry
->Name
);
339 ExFreePool(ValueInfo
);
343 DPRINT("Query value via query routine: %S\n", QueryEntry
->Name
);
345 if (QueryEntry
->Name
!= NULL
)
347 DPRINT("Callback\n");
349 RtlInitUnicodeString(&KeyName
,
352 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
353 ValueInfo
= ExAllocatePool(PagedPool
,
355 if (ValueInfo
== NULL
)
357 Status
= STATUS_NO_MEMORY
;
361 Status
= NtQueryValueKey(CurrentKeyHandle
,
363 KeyValuePartialInformation
,
367 if (!NT_SUCCESS(Status
))
369 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
370 QueryEntry
->DefaultType
,
371 QueryEntry
->DefaultData
,
372 QueryEntry
->DefaultLength
,
374 QueryEntry
->EntryContext
);
376 else if ((ValueInfo
->Type
== REG_MULTI_SZ
) &&
377 !(QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
379 DPRINT("Expand REG_MULTI_SZ type\n");
380 StringPtr
= (PWSTR
)ValueInfo
->Data
;
381 while (*StringPtr
!= 0)
383 StringLen
= (wcslen(StringPtr
) + 1) * sizeof(WCHAR
);
384 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
389 QueryEntry
->EntryContext
);
390 if(!NT_SUCCESS(Status
))
392 StringPtr
= (PWSTR
)((PUCHAR
)StringPtr
+ StringLen
);
397 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
400 ValueInfo
->DataLength
,
402 QueryEntry
->EntryContext
);
405 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
407 DPRINT("FIXME: Delete value: %S\n", QueryEntry
->Name
);
411 ExFreePool(ValueInfo
);
413 if (!NT_SUCCESS(Status
))
416 else if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOVALUE
)
418 DPRINT("Simple callback\n");
419 Status
= QueryEntry
->QueryRoutine(NULL
,
424 QueryEntry
->EntryContext
);
425 if (!NT_SUCCESS(Status
))
430 DPRINT("Enumerate values\n");
432 BufferSize
= sizeof(KEY_VALUE_FULL_INFORMATION
) + 4096;
433 FullValueInfo
= ExAllocatePool(PagedPool
,
435 if (FullValueInfo
== NULL
)
437 Status
= STATUS_NO_MEMORY
;
444 Status
= NtEnumerateValueKey(CurrentKeyHandle
,
446 KeyValueFullInformation
,
450 if (!NT_SUCCESS(Status
))
452 if ((Status
== STATUS_NO_MORE_ENTRIES
) &&
454 (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
))
456 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
458 else if (Status
== STATUS_NO_MORE_ENTRIES
)
460 Status
= STATUS_SUCCESS
;
465 if ((FullValueInfo
->Type
== REG_MULTI_SZ
) &&
466 !(QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
468 DPRINT("Expand REG_MULTI_SZ type\n");
469 StringPtr
= (PWSTR
)((PVOID
)FullValueInfo
+ FullValueInfo
->DataOffset
);
470 while (*StringPtr
!= 0)
472 StringLen
= (wcslen(StringPtr
) + 1) * sizeof(WCHAR
);
473 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
478 QueryEntry
->EntryContext
);
479 if(!NT_SUCCESS(Status
))
481 StringPtr
= (PWSTR
)((PUCHAR
)StringPtr
+ StringLen
);
486 Status
= QueryEntry
->QueryRoutine(FullValueInfo
->Name
,
488 (PVOID
)FullValueInfo
+ FullValueInfo
->DataOffset
,
489 FullValueInfo
->DataLength
,
491 QueryEntry
->EntryContext
);
494 if (!NT_SUCCESS(Status
))
497 /* FIXME: How will these be deleted? */
502 ExFreePool(FullValueInfo
);
504 if (!NT_SUCCESS(Status
))
514 if (CurrentKeyHandle
!= BaseKeyHandle
)
515 NtClose(CurrentKeyHandle
);
517 NtClose(BaseKeyHandle
);
524 RtlWriteRegistryValue(IN ULONG RelativeTo
,
529 IN ULONG ValueLength
)
535 Status
= RtlpGetRegistryHandle(RelativeTo
,
539 if (!NT_SUCCESS(Status
))
542 RtlInitUnicodeString(&Name
,
545 NtSetValueKey(KeyHandle
,
554 return(STATUS_SUCCESS
);
559 RtlFormatCurrentUserKeyPath(IN OUT PUNICODE_STRING KeyPath
)
562 RtlCreateUnicodeString(KeyPath
,
563 L
"\\Registry\\User\\.Default");
565 return(STATUS_SUCCESS
);
568 /* ------------------------------------------ Private Implementation */
572 RtlpGetRegistryHandle(ULONG RelativeTo
,
577 UNICODE_STRING KeyName
;
578 WCHAR KeyBuffer
[MAX_PATH
];
579 OBJECT_ATTRIBUTES ObjectAttributes
;
582 if (RelativeTo
& RTL_REGISTRY_HANDLE
)
584 Status
= NtDuplicateObject(PsGetCurrentProcessId(),
586 PsGetCurrentProcessId(),
590 DUPLICATE_SAME_ACCESS
);
594 if (RelativeTo
& RTL_REGISTRY_OPTIONAL
)
595 RelativeTo
&= ~RTL_REGISTRY_OPTIONAL
;
597 if (RelativeTo
>= RTL_REGISTRY_MAXIMUM
)
598 return STATUS_INVALID_PARAMETER
;
601 KeyName
.MaximumLength
= MAX_PATH
;
602 KeyName
.Buffer
= KeyBuffer
;
607 case RTL_REGISTRY_SERVICES
:
608 RtlAppendUnicodeToString(&KeyName
,
609 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
612 case RTL_REGISTRY_CONTROL
:
613 RtlAppendUnicodeToString(&KeyName
,
614 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
617 case RTL_REGISTRY_WINDOWS_NT
:
618 RtlAppendUnicodeToString(&KeyName
,
619 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
622 case RTL_REGISTRY_DEVICEMAP
:
623 RtlAppendUnicodeToString(&KeyName
,
624 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\");
627 case RTL_REGISTRY_USER
:
628 Status
= RtlFormatCurrentUserKeyPath(&KeyName
);
629 if (!NT_SUCCESS(Status
))
633 /* ReactOS specific */
634 case RTL_REGISTRY_ENUM
:
635 RtlAppendUnicodeToString(&KeyName
,
636 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
640 if (Path
[0] == L
'\\' && RelativeTo
!= RTL_REGISTRY_ABSOLUTE
)
644 RtlAppendUnicodeToString(&KeyName
,
647 DPRINT("KeyName '%wZ'\n", &KeyName
);
649 InitializeObjectAttributes(&ObjectAttributes
,
651 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
657 Status
= NtCreateKey(KeyHandle
,
667 Status
= NtOpenKey(KeyHandle
,
677 RtlpCreateRegistryKeyPath(PWSTR Path
)
679 OBJECT_ATTRIBUTES ObjectAttributes
;
680 WCHAR KeyBuffer
[MAX_PATH
];
681 UNICODE_STRING KeyName
;
687 if (_wcsnicmp(Path
, L
"\\Registry\\", 10) != 0)
689 return(STATUS_INVALID_PARAMETER
);
692 wcsncpy(KeyBuffer
, Path
, MAX_PATH
-1);
693 RtlInitUnicodeString(&KeyName
, KeyBuffer
);
695 /* Skip \\Registry\\ */
696 Current
= KeyName
.Buffer
;
697 Current
= wcschr(Current
, '\\') + 1;
698 Current
= wcschr(Current
, '\\') + 1;
701 Next
= wcschr(Current
, '\\');
711 InitializeObjectAttributes(
714 OBJ_CASE_INSENSITIVE
,
718 DPRINT("Create '%S'\n", KeyName
.Buffer
);
720 Status
= NtCreateKey(
728 if (!NT_SUCCESS(Status
))
730 DPRINT("NtCreateKey() failed with status %x\n", Status
);
742 } while (Next
!= NULL
);
744 return STATUS_SUCCESS
;