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
12 #include <ddk/ntddk.h>
14 #include <internal/ob.h>
17 #include <internal/pool.h>
18 #include <internal/registry.h>
21 #include <internal/debug.h>
27 RtlCheckRegistryKey(IN ULONG RelativeTo
,
33 Status
= RtlpGetRegistryHandle(RelativeTo
,
37 if (!NT_SUCCESS(Status
))
42 return(STATUS_SUCCESS
);
47 RtlCreateRegistryKey(IN ULONG RelativeTo
,
53 Status
= RtlpGetRegistryHandle(RelativeTo
,
57 if (!NT_SUCCESS(Status
))
62 return(STATUS_SUCCESS
);
67 RtlDeleteRegistryValue(IN ULONG RelativeTo
,
75 Status
= RtlpGetRegistryHandle(RelativeTo
,
79 if (!NT_SUCCESS(Status
))
82 RtlInitUnicodeString(&Name
,
85 NtDeleteValueKey(KeyHandle
,
90 return(STATUS_SUCCESS
);
95 RtlOpenCurrentUser(IN ACCESS_MASK DesiredAccess
,
96 OUT PHANDLE KeyHandle
)
98 OBJECT_ATTRIBUTES ObjectAttributes
;
99 UNICODE_STRING KeyPath
= UNICODE_STRING_INITIALIZER(L
"\\Registry\\User\\.Default");
102 Status
= RtlFormatCurrentUserKeyPath(&KeyPath
);
103 if (NT_SUCCESS(Status
))
105 InitializeObjectAttributes(&ObjectAttributes
,
107 OBJ_CASE_INSENSITIVE
,
110 Status
= NtOpenKey(KeyHandle
,
113 RtlFreeUnicodeString(&KeyPath
);
114 if (NT_SUCCESS(Status
))
115 return(STATUS_SUCCESS
);
118 InitializeObjectAttributes(&ObjectAttributes
,
120 OBJ_CASE_INSENSITIVE
,
123 Status
= NtOpenKey(KeyHandle
,
131 RtlQueryRegistryValues(IN ULONG RelativeTo
,
133 IN PRTL_QUERY_REGISTRY_TABLE QueryTable
,
135 IN PVOID Environment
)
138 HANDLE BaseKeyHandle
;
139 HANDLE CurrentKeyHandle
;
140 PRTL_QUERY_REGISTRY_TABLE QueryEntry
;
141 OBJECT_ATTRIBUTES ObjectAttributes
;
142 UNICODE_STRING KeyName
;
143 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
144 PKEY_VALUE_FULL_INFORMATION FullValueInfo
;
151 DPRINT("RtlQueryRegistryValues() called\n");
153 BaseKeyHandle
= NULL
;
154 CurrentKeyHandle
= NULL
;
157 Status
= RtlpGetRegistryHandle(RelativeTo
,
161 if (!NT_SUCCESS(Status
))
163 DPRINT("RtlpGetRegistryHandle() failed with status %x\n", Status
);
167 CurrentKeyHandle
= BaseKeyHandle
;
168 QueryEntry
= QueryTable
;
169 while ((QueryEntry
->QueryRoutine
!= NULL
) ||
170 (QueryEntry
->Name
!= NULL
))
174 packet.sys has this code which calls this (and fails here) with:
176 RtlZeroMemory(ParamTable, sizeof(ParamTable));
178 // change to the linkage key
180 ParamTable[0].QueryRoutine = NULL; // NOTE: QueryRoutine is set to NULL
181 ParamTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
182 ParamTable[0].Name = L"Linkage";
184 // Get the name of the mac driver we should bind to
186 ParamTable[1].QueryRoutine = PacketQueryRegistryRoutine;
187 ParamTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
188 ParamTable[1].Name = L"Bind";
189 ParamTable[1].EntryContext = (PVOID)MacDriverName;
190 ParamTable[1].DefaultType = REG_MULTI_SZ;
192 Status = RtlQueryRegistryValues(
193 IN ULONG RelativeTo = RTL_REGISTRY_ABSOLUTE,
194 IN PWSTR Path = Path,
195 IN PRTL_QUERY_REGISTRY_TABLE QueryTable = ParamTable,
196 IN PVOID Context = NULL,
197 IN PVOID Environment = NULL);
201 //if ((QueryEntry->QueryRoutine == NULL) &&
202 // ((QueryEntry->Flags & (RTL_QUERY_REGISTRY_SUBKEY | RTL_QUERY_REGISTRY_DIRECT)) != 0))
203 // Which is more correct?
204 if ((QueryEntry
->QueryRoutine
== NULL
) &&
205 ((QueryEntry
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
) != 0))
207 DPRINT("Bad parameters\n");
208 Status
= STATUS_INVALID_PARAMETER
;
212 DPRINT("Name: %S\n", QueryEntry
->Name
);
214 if (((QueryEntry
->Flags
& (RTL_QUERY_REGISTRY_SUBKEY
| RTL_QUERY_REGISTRY_TOPKEY
)) != 0) &&
215 (BaseKeyHandle
!= CurrentKeyHandle
))
217 NtClose(CurrentKeyHandle
);
218 CurrentKeyHandle
= BaseKeyHandle
;
221 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_SUBKEY
)
223 DPRINT("Open new subkey: %S\n", QueryEntry
->Name
);
225 RtlInitUnicodeString(&KeyName
,
227 InitializeObjectAttributes(&ObjectAttributes
,
229 OBJ_CASE_INSENSITIVE
,
232 Status
= NtOpenKey(&CurrentKeyHandle
,
235 if (!NT_SUCCESS(Status
))
238 else if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DIRECT
)
240 DPRINT("Query value directly: %S\n", QueryEntry
->Name
);
242 RtlInitUnicodeString(&KeyName
,
245 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
246 ValueInfo
= ExAllocatePool(PagedPool
, BufferSize
);
247 if (ValueInfo
== NULL
)
249 Status
= STATUS_NO_MEMORY
;
253 memset(ValueInfo
, 0, BufferSize
);
255 Status
= ZwQueryValueKey(CurrentKeyHandle
,
257 KeyValuePartialInformation
,
261 if (!NT_SUCCESS(Status
))
263 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
)
265 ExFreePool(ValueInfo
);
266 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
270 if (QueryEntry
->DefaultType
== REG_SZ
)
272 PUNICODE_STRING ValueString
;
273 PUNICODE_STRING SourceString
;
275 SourceString
= (PUNICODE_STRING
)QueryEntry
->DefaultData
;
276 ValueString
= (PUNICODE_STRING
)QueryEntry
->EntryContext
;
277 if (ValueString
->Buffer
== 0)
279 ValueString
->Length
= SourceString
->Length
;
280 ValueString
->MaximumLength
= SourceString
->MaximumLength
;
281 ValueString
->Buffer
= ExAllocatePool(PagedPool
,
282 ValueString
->MaximumLength
);
283 if (!ValueString
->Buffer
)
285 ValueString
->Buffer
[0] = 0;
286 memcpy(ValueString
->Buffer
,
287 SourceString
->Buffer
,
288 SourceString
->MaximumLength
);
292 ValueString
->Length
= RtlMin(SourceString
->Length
,
293 ValueString
->MaximumLength
- sizeof(WCHAR
));
294 memcpy(ValueString
->Buffer
,
295 SourceString
->Buffer
,
296 ValueString
->Length
);
297 ((PWSTR
)ValueString
->Buffer
)[ValueString
->Length
/ sizeof(WCHAR
)] = 0;
302 memcpy(QueryEntry
->EntryContext
,
303 QueryEntry
->DefaultData
,
304 QueryEntry
->DefaultLength
);
306 Status
= STATUS_SUCCESS
;
310 if (ValueInfo
->Type
== REG_SZ
||
311 ValueInfo
->Type
== REG_MULTI_SZ
||
312 ValueInfo
->Type
== REG_EXPAND_SZ
)
314 PUNICODE_STRING ValueString
;
316 ValueString
= (PUNICODE_STRING
)QueryEntry
->EntryContext
;
317 if (ValueString
->Buffer
== 0)
319 RtlInitUnicodeString(ValueString
,
321 ValueString
->MaximumLength
= ValueInfo
->DataLength
+ sizeof(WCHAR
); //256 * sizeof(WCHAR);
322 ValueString
->Buffer
= ExAllocatePool(PagedPool
,
323 ValueString
->MaximumLength
);
324 if (!ValueString
->Buffer
)
326 ValueString
->Buffer
[0] = 0;
328 ValueString
->Length
= RtlMin(ValueInfo
->DataLength
,
329 ValueString
->MaximumLength
- sizeof(WCHAR
));
330 memcpy(ValueString
->Buffer
,
332 ValueString
->Length
);
333 ((PWSTR
)ValueString
->Buffer
)[ValueString
->Length
/ sizeof(WCHAR
)] = 0;
337 memcpy(QueryEntry
->EntryContext
,
339 ValueInfo
->DataLength
);
343 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
345 DPRINT("FIXME: Delete value: %S\n", QueryEntry
->Name
);
349 ExFreePool(ValueInfo
);
353 DPRINT("Query value via query routine: %S\n", QueryEntry
->Name
);
355 if (QueryEntry
->Name
!= NULL
)
357 DPRINT("Callback\n");
359 RtlInitUnicodeString(&KeyName
,
362 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
363 ValueInfo
= ExAllocatePool(PagedPool
,
365 if (ValueInfo
== NULL
)
367 Status
= STATUS_NO_MEMORY
;
371 Status
= NtQueryValueKey(CurrentKeyHandle
,
373 KeyValuePartialInformation
,
377 if (!NT_SUCCESS(Status
))
379 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
380 QueryEntry
->DefaultType
,
381 QueryEntry
->DefaultData
,
382 QueryEntry
->DefaultLength
,
384 QueryEntry
->EntryContext
);
386 else if ((ValueInfo
->Type
== REG_MULTI_SZ
) &&
387 !(QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
389 DPRINT("Expand REG_MULTI_SZ type\n");
390 StringPtr
= (PWSTR
)ValueInfo
->Data
;
391 while (*StringPtr
!= 0)
393 StringLen
= (wcslen(StringPtr
) + 1) * sizeof(WCHAR
);
394 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
399 QueryEntry
->EntryContext
);
400 if(!NT_SUCCESS(Status
))
402 StringPtr
= (PWSTR
)((PUCHAR
)StringPtr
+ StringLen
);
407 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
410 ValueInfo
->DataLength
,
412 QueryEntry
->EntryContext
);
415 if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_DELETE
)
417 DPRINT("FIXME: Delete value: %S\n", QueryEntry
->Name
);
421 ExFreePool(ValueInfo
);
423 if (!NT_SUCCESS(Status
))
426 else if (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOVALUE
)
428 DPRINT("Simple callback\n");
429 Status
= QueryEntry
->QueryRoutine(NULL
,
434 QueryEntry
->EntryContext
);
435 if (!NT_SUCCESS(Status
))
440 DPRINT("Enumerate values\n");
442 BufferSize
= sizeof(KEY_VALUE_FULL_INFORMATION
) + 4096;
443 FullValueInfo
= ExAllocatePool(PagedPool
,
445 if (FullValueInfo
== NULL
)
447 Status
= STATUS_NO_MEMORY
;
454 Status
= NtEnumerateValueKey(CurrentKeyHandle
,
456 KeyValueFullInformation
,
460 if (!NT_SUCCESS(Status
))
462 if ((Status
== STATUS_NO_MORE_ENTRIES
) &&
464 (QueryEntry
->Flags
& RTL_QUERY_REGISTRY_REQUIRED
))
466 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
468 else if (Status
== STATUS_NO_MORE_ENTRIES
)
470 Status
= STATUS_SUCCESS
;
475 if ((FullValueInfo
->Type
== REG_MULTI_SZ
) &&
476 !(QueryEntry
->Flags
& RTL_QUERY_REGISTRY_NOEXPAND
))
478 DPRINT("Expand REG_MULTI_SZ type\n");
480 StringPtr
= (PWSTR
)(FullValueInfo
+ FullValueInfo
->DataOffset
);
482 StringPtr
= (PWSTR
)((PVOID
)FullValueInfo
+ FullValueInfo
->DataOffset
);
484 while (*StringPtr
!= 0)
486 StringLen
= (wcslen(StringPtr
) + 1) * sizeof(WCHAR
);
487 Status
= QueryEntry
->QueryRoutine(QueryEntry
->Name
,
492 QueryEntry
->EntryContext
);
493 if(!NT_SUCCESS(Status
))
495 StringPtr
= (PWSTR
)((PUCHAR
)StringPtr
+ StringLen
);
500 Status
= QueryEntry
->QueryRoutine(FullValueInfo
->Name
,
503 FullValueInfo
+ FullValueInfo
->DataOffset
,
505 (PVOID
)FullValueInfo
+ FullValueInfo
->DataOffset
,
507 FullValueInfo
->DataLength
,
509 QueryEntry
->EntryContext
);
512 if (!NT_SUCCESS(Status
))
515 /* FIXME: How will these be deleted? */
520 ExFreePool(FullValueInfo
);
522 if (!NT_SUCCESS(Status
))
532 if (CurrentKeyHandle
!= BaseKeyHandle
)
533 NtClose(CurrentKeyHandle
);
535 NtClose(BaseKeyHandle
);
542 RtlWriteRegistryValue(IN ULONG RelativeTo
,
547 IN ULONG ValueLength
)
553 Status
= RtlpGetRegistryHandle(RelativeTo
,
557 if (!NT_SUCCESS(Status
))
560 RtlInitUnicodeString(&Name
,
563 NtSetValueKey(KeyHandle
,
572 return(STATUS_SUCCESS
);
577 RtlFormatCurrentUserKeyPath(IN OUT PUNICODE_STRING KeyPath
)
580 RtlCreateUnicodeString(KeyPath
,
581 L
"\\Registry\\User\\.Default");
583 return(STATUS_SUCCESS
);
586 /* ------------------------------------------ Private Implementation */
590 RtlpGetRegistryHandle(ULONG RelativeTo
,
595 UNICODE_STRING KeyName
;
596 WCHAR KeyBuffer
[MAX_PATH
];
597 OBJECT_ATTRIBUTES ObjectAttributes
;
600 if (RelativeTo
& RTL_REGISTRY_HANDLE
)
602 Status
= NtDuplicateObject(PsGetCurrentProcessId(),
604 PsGetCurrentProcessId(),
608 DUPLICATE_SAME_ACCESS
);
612 if (RelativeTo
& RTL_REGISTRY_OPTIONAL
)
613 RelativeTo
&= ~RTL_REGISTRY_OPTIONAL
;
615 if (RelativeTo
>= RTL_REGISTRY_MAXIMUM
)
616 return STATUS_INVALID_PARAMETER
;
619 KeyName
.MaximumLength
= MAX_PATH
;
620 KeyName
.Buffer
= KeyBuffer
;
625 case RTL_REGISTRY_SERVICES
:
626 RtlAppendUnicodeToString(&KeyName
,
627 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
630 case RTL_REGISTRY_CONTROL
:
631 RtlAppendUnicodeToString(&KeyName
,
632 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\");
635 case RTL_REGISTRY_WINDOWS_NT
:
636 RtlAppendUnicodeToString(&KeyName
,
637 L
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
640 case RTL_REGISTRY_DEVICEMAP
:
641 RtlAppendUnicodeToString(&KeyName
,
642 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\");
645 case RTL_REGISTRY_USER
:
646 Status
= RtlFormatCurrentUserKeyPath(&KeyName
);
647 if (!NT_SUCCESS(Status
))
651 /* ReactOS specific */
652 case RTL_REGISTRY_ENUM
:
653 RtlAppendUnicodeToString(&KeyName
,
654 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
658 if (Path
[0] == L
'\\' && RelativeTo
!= RTL_REGISTRY_ABSOLUTE
)
662 RtlAppendUnicodeToString(&KeyName
,
665 DPRINT("KeyName '%wZ'\n", &KeyName
);
667 InitializeObjectAttributes(&ObjectAttributes
,
669 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
675 Status
= NtCreateKey(KeyHandle
,
685 Status
= NtOpenKey(KeyHandle
,
695 RtlpCreateRegistryKeyPath(PWSTR Path
)
697 OBJECT_ATTRIBUTES ObjectAttributes
;
698 WCHAR KeyBuffer
[MAX_PATH
];
699 UNICODE_STRING KeyName
;
705 if (_wcsnicmp(Path
, L
"\\Registry\\", 10) != 0)
707 return(STATUS_INVALID_PARAMETER
);
710 wcsncpy(KeyBuffer
, Path
, MAX_PATH
-1);
711 RtlInitUnicodeString(&KeyName
, KeyBuffer
);
713 /* Skip \\Registry\\ */
714 Current
= KeyName
.Buffer
;
715 Current
= wcschr(Current
, '\\') + 1;
716 Current
= wcschr(Current
, '\\') + 1;
719 Next
= wcschr(Current
, '\\');
729 InitializeObjectAttributes(
732 OBJ_CASE_INSENSITIVE
,
736 DPRINT("Create '%S'\n", KeyName
.Buffer
);
738 Status
= NtCreateKey(
746 if (!NT_SUCCESS(Status
))
748 DPRINT("NtCreateKey() failed with status %x\n", Status
);
760 } while (Next
!= NULL
);
762 return STATUS_SUCCESS
;