4 * Copyright (C) 2014 Timo Kreuzer <timo.kreuzer@reactos.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 DBG_DEFAULT_CHANNEL(REGISTRY
);
28 static PCMHIVE CmHive
;
29 static PCM_KEY_NODE RootKeyNode
;
30 static HKEY CurrentControlSetKey
;
39 UNREFERENCED_PARAMETER(Paged
);
40 UNREFERENCED_PARAMETER(Tag
);
42 return FrLdrTempAlloc(Size
, Tag
);
51 UNREFERENCED_PARAMETER(Quota
);
52 FrLdrTempFree(Ptr
, 0);
61 TRACE("RegImportBinaryHive(%p, 0x%lx)\n", ChunkBase
, ChunkSize
);
63 /* Allocate and initialize the hive */
64 CmHive
= CmpAllocate(sizeof(CMHIVE
), FALSE
, 'eviH');
65 Status
= HvInitialize(&CmHive
->Hive
,
66 HINIT_FLAT
, // HINIT_MEMORY_INPLACE
78 if (!NT_SUCCESS(Status
))
81 ERR("Corrupted hive %p!\n", ChunkBase
);
85 /* Save the root key node */
86 RootKeyNode
= (PCM_KEY_NODE
)HvGetCell(&CmHive
->Hive
, CmHive
->Hive
.BaseBlock
->RootCell
);
88 TRACE("RegImportBinaryHive done\n");
93 RegInitCurrentControlSet(
94 _In_ BOOLEAN LastKnownGood
)
96 WCHAR ControlSetKeyName
[80];
100 ULONG DefaultSet
= 0;
101 ULONG LastKnownGoodSet
= 0;
104 TRACE("RegInitCurrentControlSet\n");
106 Error
= RegOpenKey(NULL
,
107 L
"\\Registry\\Machine\\SYSTEM\\Select",
109 if (Error
!= ERROR_SUCCESS
)
111 ERR("RegOpenKey() failed (Error %u)\n", (int)Error
);
115 DataSize
= sizeof(ULONG
);
116 Error
= RegQueryValue(SelectKey
,
121 if (Error
!= ERROR_SUCCESS
)
123 ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error
);
127 DataSize
= sizeof(ULONG
);
128 Error
= RegQueryValue(SelectKey
,
131 (PUCHAR
)&LastKnownGoodSet
,
133 if (Error
!= ERROR_SUCCESS
)
135 ERR("RegQueryValue('LastKnownGood') failed (Error %u)\n", (int)Error
);
139 CurrentSet
= (LastKnownGood
) ? LastKnownGoodSet
: DefaultSet
;
140 wcscpy(ControlSetKeyName
, L
"ControlSet");
144 wcscat(ControlSetKeyName
, L
"001");
147 wcscat(ControlSetKeyName
, L
"002");
150 wcscat(ControlSetKeyName
, L
"003");
153 wcscat(ControlSetKeyName
, L
"004");
156 wcscat(ControlSetKeyName
, L
"005");
160 Error
= RegOpenKey(NULL
,
161 L
"\\Registry\\Machine\\SYSTEM",
163 if (Error
!= ERROR_SUCCESS
)
165 ERR("RegOpenKey(SystemKey) failed (Error %lu)\n", Error
);
169 Error
= RegOpenKey(SystemKey
,
171 &CurrentControlSetKey
);
172 if (Error
!= ERROR_SUCCESS
)
174 ERR("RegOpenKey(CurrentControlSetKey) failed (Error %lu)\n", Error
);
178 TRACE("RegInitCurrentControlSet done\n");
179 return ERROR_SUCCESS
;
185 _Out_ PUNICODE_STRING NextElement
,
186 _Inout_ PUNICODE_STRING RemainingPath
)
188 /* Check if there are any characters left */
189 if (RemainingPath
->Length
< sizeof(WCHAR
))
191 /* Nothing left, bail out early */
195 /* The next path elements starts with the remaining path */
196 NextElement
->Buffer
= RemainingPath
->Buffer
;
198 /* Loop until the path element ends */
199 while ((RemainingPath
->Length
>= sizeof(WCHAR
)) &&
200 (RemainingPath
->Buffer
[0] != '\\'))
202 /* Skip this character */
203 RemainingPath
->Buffer
++;
204 RemainingPath
->Length
-= sizeof(WCHAR
);
207 NextElement
->Length
= (USHORT
)(RemainingPath
->Buffer
- NextElement
->Buffer
) * sizeof(WCHAR
);
208 NextElement
->MaximumLength
= NextElement
->Length
;
210 /* Check if the path element ended with a path separator */
211 if (RemainingPath
->Length
>= sizeof(WCHAR
))
213 /* Skip the path separator */
214 ASSERT(RemainingPath
->Buffer
[0] == '\\');
215 RemainingPath
->Buffer
++;
216 RemainingPath
->Length
-= sizeof(WCHAR
);
219 /* Return whether we got any characters */
228 _Inout_ ULONG
* NameSize
,
229 _Out_opt_ PHKEY SubKey
)
231 PHHIVE Hive
= &CmHive
->Hive
;
232 PCM_KEY_NODE KeyNode
, SubKeyNode
;
233 HCELL_INDEX CellIndex
;
236 TRACE("RegEnumKey(%p, %lu, %p, %p->%u)\n",
237 Key
, Index
, Name
, NameSize
, NameSize
? *NameSize
: 0);
239 /* Get the key node */
240 KeyNode
= (PCM_KEY_NODE
)Key
;
241 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
243 CellIndex
= CmpFindSubKeyByNumber(Hive
, KeyNode
, Index
);
244 if (CellIndex
== HCELL_NIL
)
246 TRACE("RegEnumKey index out of bounds (%d) in key (%.*s)\n",
247 Index
, KeyNode
->NameLength
, KeyNode
->Name
);
248 return ERROR_NO_MORE_ITEMS
;
251 /* Get the value cell */
252 SubKeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, CellIndex
);
253 ASSERT(SubKeyNode
!= NULL
);
254 ASSERT(SubKeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
256 if (SubKeyNode
->Flags
& KEY_COMP_NAME
)
258 NameLength
= CmpCompressedNameSize(SubKeyNode
->Name
, SubKeyNode
->NameLength
);
260 /* Compressed name */
261 CmpCopyCompressedName(Name
,
264 SubKeyNode
->NameLength
);
268 NameLength
= SubKeyNode
->NameLength
;
271 RtlCopyMemory(Name
, SubKeyNode
->Name
,
272 min(*NameSize
, SubKeyNode
->NameLength
));
275 if (*NameSize
>= NameLength
+ sizeof(WCHAR
))
277 Name
[NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
280 *NameSize
= NameLength
+ sizeof(WCHAR
);
282 /**/HvReleaseCell(Hive
, CellIndex
);/**/
285 *SubKey
= (HKEY
)SubKeyNode
;
287 TRACE("RegEnumKey done -> %u, '%.*S'\n", *NameSize
, *NameSize
, Name
);
288 return ERROR_SUCCESS
;
294 _In_z_ PCWSTR KeyName
,
297 UNICODE_STRING RemainingPath
, SubKeyName
;
298 UNICODE_STRING CurrentControlSet
= RTL_CONSTANT_STRING(L
"CurrentControlSet");
299 PHHIVE Hive
= &CmHive
->Hive
;
300 PCM_KEY_NODE KeyNode
;
301 HCELL_INDEX CellIndex
;
302 TRACE("RegOpenKey(%p, '%S', %p)\n", ParentKey
, KeyName
, Key
);
304 /* Initialize the remaining path name */
305 RtlInitUnicodeString(&RemainingPath
, KeyName
);
307 /* Get the parent key node */
308 KeyNode
= (PCM_KEY_NODE
)ParentKey
;
310 /* Check if we have a parent key */
313 UNICODE_STRING SubKeyName1
, SubKeyName2
, SubKeyName3
;
314 UNICODE_STRING RegistryPath
= RTL_CONSTANT_STRING(L
"Registry");
315 UNICODE_STRING MachinePath
= RTL_CONSTANT_STRING(L
"MACHINE");
316 UNICODE_STRING SystemPath
= RTL_CONSTANT_STRING(L
"SYSTEM");
317 TRACE("RegOpenKey: absolute path\n");
319 if ((RemainingPath
.Length
< sizeof(WCHAR
)) ||
320 RemainingPath
.Buffer
[0] != '\\')
322 /* The key path is not absolute */
323 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName
, &RemainingPath
);
324 return ERROR_PATH_NOT_FOUND
;
327 /* Skip initial path separator */
328 RemainingPath
.Buffer
++;
329 RemainingPath
.Length
-= sizeof(WCHAR
);
331 /* Get the first 3 path elements */
332 GetNextPathElement(&SubKeyName1
, &RemainingPath
);
333 GetNextPathElement(&SubKeyName2
, &RemainingPath
);
334 GetNextPathElement(&SubKeyName3
, &RemainingPath
);
335 TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1
, &SubKeyName2
, &SubKeyName3
);
337 /* Check if we have the correct path */
338 if (!RtlEqualUnicodeString(&SubKeyName1
, &RegistryPath
, TRUE
) ||
339 !RtlEqualUnicodeString(&SubKeyName2
, &MachinePath
, TRUE
) ||
340 !RtlEqualUnicodeString(&SubKeyName3
, &SystemPath
, TRUE
))
342 /* The key path is not inside HKLM\Machine\System */
343 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName
, &RemainingPath
);
344 return ERROR_PATH_NOT_FOUND
;
347 /* Use the root key */
348 KeyNode
= RootKeyNode
;
351 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
353 /* Check if this is the root key */
354 if (KeyNode
== RootKeyNode
)
356 UNICODE_STRING TempPath
= RemainingPath
;
358 /* Get the first path element */
359 GetNextPathElement(&SubKeyName
, &TempPath
);
361 /* Check if this is CurrentControlSet */
362 if (RtlEqualUnicodeString(&SubKeyName
, &CurrentControlSet
, TRUE
))
364 /* Use the CurrentControlSetKey and update the remaining path */
365 KeyNode
= (PCM_KEY_NODE
)CurrentControlSetKey
;
366 RemainingPath
= TempPath
;
370 TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath
);
372 /* Loop while there are path elements */
373 while (GetNextPathElement(&SubKeyName
, &RemainingPath
))
375 TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName
);
377 /* Get the next sub key */
378 CellIndex
= CmpFindSubKeyByName(Hive
, KeyNode
, &SubKeyName
);
379 if (CellIndex
== HCELL_NIL
)
381 ERR("Did not find sub key '%wZ' (full %S)\n", &SubKeyName
, KeyName
);
382 return ERROR_PATH_NOT_FOUND
;
385 /* Get the found key */
386 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Hive
, CellIndex
);
390 *Key
= (HKEY
)KeyNode
;
392 TRACE("RegOpenKey done\n");
393 return ERROR_SUCCESS
;
400 _In_ PCM_KEY_VALUE ValueCell
,
401 _Out_opt_ ULONG
* Type
,
402 _Out_opt_ PUCHAR Data
,
403 _Inout_opt_ ULONG
* DataSize
)
408 /* Does the caller want the type? */
410 *Type
= ValueCell
->Type
;
412 /* Does the caller provide DataSize? */
413 if (DataSize
!= NULL
)
415 // NOTE: CmpValueToData doesn't support big data (the function will
416 // bugcheck if so), FreeLdr is not supposed to read such data.
417 // If big data is needed, use instead CmpGetValueData.
418 // CmpGetValueData(Hive, ValueCell, DataSize, &DataCell, ...);
419 DataCell
= CmpValueToData(Hive
, ValueCell
, &DataLength
);
421 /* Does the caller want the data? */
422 if ((Data
!= NULL
) && (*DataSize
!= 0))
426 min(*DataSize
, DataLength
));
429 /* Return the actual data length */
430 *DataSize
= DataLength
;
437 _In_z_ PCWSTR ValueName
,
438 _Out_opt_ ULONG
* Type
,
439 _Out_opt_ PUCHAR Data
,
440 _Inout_opt_ ULONG
* DataSize
)
442 PHHIVE Hive
= &CmHive
->Hive
;
443 PCM_KEY_NODE KeyNode
;
444 PCM_KEY_VALUE ValueCell
;
445 HCELL_INDEX CellIndex
;
446 UNICODE_STRING ValueNameString
;
448 TRACE("RegQueryValue(%p, '%S', %p, %p, %p)\n",
449 Key
, ValueName
, Type
, Data
, DataSize
);
451 /* Get the key node */
452 KeyNode
= (PCM_KEY_NODE
)Key
;
453 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
455 /* Initialize value name string */
456 RtlInitUnicodeString(&ValueNameString
, ValueName
);
457 CellIndex
= CmpFindValueByName(Hive
, KeyNode
, &ValueNameString
);
458 if (CellIndex
== HCELL_NIL
)
460 TRACE("RegQueryValue value not found in key (%.*s)\n",
461 KeyNode
->NameLength
, KeyNode
->Name
);
462 return ERROR_FILE_NOT_FOUND
;
465 /* Get the value cell */
466 ValueCell
= (PCM_KEY_VALUE
)HvGetCell(Hive
, CellIndex
);
467 ASSERT(ValueCell
!= NULL
);
469 RepGetValueData(Hive
, ValueCell
, Type
, Data
, DataSize
);
471 HvReleaseCell(Hive
, CellIndex
);
473 TRACE("RegQueryValue success\n");
474 return ERROR_SUCCESS
;
478 * NOTE: This function is currently unused in FreeLdr; however it is kept here
479 * as an implementation reference of RegEnumValue using CMLIB that may be used
480 * elsewhere in ReactOS.
487 _Out_ PWCHAR ValueName
,
488 _Inout_ ULONG
* NameSize
,
489 _Out_opt_ ULONG
* Type
,
490 _Out_opt_ PUCHAR Data
,
491 _Inout_opt_ ULONG
* DataSize
)
493 PHHIVE Hive
= &CmHive
->Hive
;
494 PCM_KEY_NODE KeyNode
;
495 PCELL_DATA ValueListCell
;
496 PCM_KEY_VALUE ValueCell
;
499 TRACE("RegEnumValue(%p, %lu, %S, %p, %p, %p, %p (%lu))\n",
500 Key
, Index
, ValueName
, NameSize
, Type
, Data
, DataSize
, *DataSize
);
502 /* Get the key node */
503 KeyNode
= (PCM_KEY_NODE
)Key
;
504 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
506 /* Check if the index is valid */
507 if ((KeyNode
->ValueList
.Count
== 0) ||
508 (KeyNode
->ValueList
.List
== HCELL_NIL
) ||
509 (Index
>= KeyNode
->ValueList
.Count
))
511 ERR("RegEnumValue: index invalid\n");
512 return ERROR_NO_MORE_ITEMS
;
515 ValueListCell
= (PCELL_DATA
)HvGetCell(Hive
, KeyNode
->ValueList
.List
);
516 ASSERT(ValueListCell
!= NULL
);
518 /* Get the value cell */
519 ValueCell
= (PCM_KEY_VALUE
)HvGetCell(Hive
, ValueListCell
->KeyList
[Index
]);
520 ASSERT(ValueCell
!= NULL
);
521 ASSERT(ValueCell
->Signature
== CM_KEY_VALUE_SIGNATURE
);
523 if (ValueCell
->Flags
& VALUE_COMP_NAME
)
525 NameLength
= CmpCompressedNameSize(ValueCell
->Name
, ValueCell
->NameLength
);
527 /* Compressed name */
528 CmpCopyCompressedName(ValueName
,
531 ValueCell
->NameLength
);
535 NameLength
= ValueCell
->NameLength
;
538 RtlCopyMemory(ValueName
, ValueCell
->Name
,
539 min(*NameSize
, ValueCell
->NameLength
));
542 if (*NameSize
>= NameLength
+ sizeof(WCHAR
))
544 ValueName
[NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
547 *NameSize
= NameLength
+ sizeof(WCHAR
);
549 RepGetValueData(Hive
, ValueCell
, Type
, Data
, DataSize
);
551 HvReleaseCell(Hive
, ValueListCell
->KeyList
[Index
]);
552 HvReleaseCell(Hive
, KeyNode
->ValueList
.List
);
554 TRACE("RegEnumValue done -> %u, '%.*S'\n", *NameSize
, *NameSize
, ValueName
);
555 return ERROR_SUCCESS
;