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.
25 DBG_DEFAULT_CHANNEL(REGISTRY
);
27 static PCMHIVE CmHive
;
28 static PCM_KEY_NODE RootKeyNode
;
29 static FRLDRHKEY CurrentControlSetKey
;
37 TRACE("RegImportBinaryHive(%p, 0x%lx)\n", ChunkBase
, ChunkSize
);
39 /* Allocate and initialize the hive */
40 CmHive
= FrLdrTempAlloc(sizeof(CMHIVE
), 'eviH');
41 Status
= HvInitialize(&CmHive
->Hive
,
54 if (!NT_SUCCESS(Status
))
56 FrLdrTempFree(CmHive
, 'eviH');
57 ERR("Invalid hive Signature!\n");
61 /* Save the root key node */
62 RootKeyNode
= HvGetCell(&CmHive
->Hive
, CmHive
->Hive
.BaseBlock
->RootCell
);
64 TRACE("RegImportBinaryHive done\n");
69 RegInitializeRegistry(VOID
)
76 RegInitCurrentControlSet(
77 _In_ BOOLEAN LastKnownGood
)
79 WCHAR ControlSetKeyName
[80];
84 ULONG LastKnownGoodSet
= 0;
87 TRACE("RegInitCurrentControlSet\n");
89 Error
= RegOpenKey(NULL
,
90 L
"\\Registry\\Machine\\SYSTEM\\Select",
92 if (Error
!= ERROR_SUCCESS
)
94 ERR("RegOpenKey() failed (Error %u)\n", (int)Error
);
98 DataSize
= sizeof(ULONG
);
99 Error
= RegQueryValue(SelectKey
,
104 if (Error
!= ERROR_SUCCESS
)
106 ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error
);
110 DataSize
= sizeof(ULONG
);
111 Error
= RegQueryValue(SelectKey
,
114 (PUCHAR
)&LastKnownGoodSet
,
116 if (Error
!= ERROR_SUCCESS
)
118 ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error
);
122 CurrentSet
= (LastKnownGood
== TRUE
) ? LastKnownGoodSet
: DefaultSet
;
123 wcscpy(ControlSetKeyName
, L
"ControlSet");
127 wcscat(ControlSetKeyName
, L
"001");
130 wcscat(ControlSetKeyName
, L
"002");
133 wcscat(ControlSetKeyName
, L
"003");
136 wcscat(ControlSetKeyName
, L
"004");
139 wcscat(ControlSetKeyName
, L
"005");
143 Error
= RegOpenKey(NULL
,
144 L
"\\Registry\\Machine\\SYSTEM",
146 if (Error
!= ERROR_SUCCESS
)
148 ERR("RegOpenKey(SystemKey) failed (Error %lu)\n", Error
);
152 Error
= RegOpenKey(SystemKey
,
154 &CurrentControlSetKey
);
155 if (Error
!= ERROR_SUCCESS
)
157 ERR("RegOpenKey(CurrentControlSetKey) failed (Error %lu)\n", Error
);
161 TRACE("RegInitCurrentControlSet done\n");
162 return ERROR_SUCCESS
;
168 _Out_ PUNICODE_STRING NextElement
,
169 _Inout_ PUNICODE_STRING RemainingPath
)
171 /* Check if there are any characters left */
172 if (RemainingPath
->Length
< sizeof(WCHAR
))
174 /* Nothing left, bail out early */
178 /* The next path elements starts with the remaining path */
179 NextElement
->Buffer
= RemainingPath
->Buffer
;
181 /* Loop until the path element ends */
182 while ((RemainingPath
->Length
>= sizeof(WCHAR
)) &&
183 (RemainingPath
->Buffer
[0] != '\\'))
185 /* Skip this character */
186 RemainingPath
->Buffer
++;
187 RemainingPath
->Length
-= sizeof(WCHAR
);
190 NextElement
->Length
= (RemainingPath
->Buffer
- NextElement
->Buffer
) * sizeof(WCHAR
);
191 NextElement
->MaximumLength
= NextElement
->Length
;
193 /* Check if the path element ended with a path separator */
194 if (RemainingPath
->Length
>= sizeof(WCHAR
))
196 /* Skip the path separator */
197 ASSERT(RemainingPath
->Buffer
[0] == '\\');
198 RemainingPath
->Buffer
++;
199 RemainingPath
->Length
-= sizeof(WCHAR
);
202 /* Return whether we got any characters */
208 RegpFindSubkeyInIndex(
210 _In_ PCM_KEY_INDEX IndexCell
,
211 _In_ PUNICODE_STRING SubKeyName
)
213 PCM_KEY_NODE SubKeyNode
;
215 TRACE("RegpFindSubkeyInIndex('%wZ')\n", SubKeyName
);
217 /* Check the cell type */
218 if ((IndexCell
->Signature
== CM_KEY_INDEX_ROOT
) ||
219 (IndexCell
->Signature
== CM_KEY_INDEX_LEAF
))
223 /* Enumerate subindex cells */
224 for (i
= 0; i
< IndexCell
->Count
; i
++)
226 /* Get the subindex cell and call the function recursively */
227 PCM_KEY_INDEX SubIndexCell
= HvGetCell(Hive
, IndexCell
->List
[i
]);
229 SubKeyNode
= RegpFindSubkeyInIndex(Hive
, SubIndexCell
, SubKeyName
);
230 if (SubKeyNode
!= NULL
)
236 else if ((IndexCell
->Signature
== CM_KEY_FAST_LEAF
) ||
237 (IndexCell
->Signature
== CM_KEY_HASH_LEAF
))
239 /* Directly enumerate subkey nodes */
240 PCM_KEY_FAST_INDEX HashCell
= (PCM_KEY_FAST_INDEX
)IndexCell
;
241 for (i
= 0; i
< HashCell
->Count
; i
++)
243 SubKeyNode
= HvGetCell(Hive
, HashCell
->List
[i
].Cell
);
244 ASSERT(SubKeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
246 TRACE(" RegpFindSubkeyInIndex: checking '%.*s'\n",
247 SubKeyNode
->NameLength
, SubKeyNode
->Name
);
248 if (CmCompareKeyName(SubKeyNode
, SubKeyName
, TRUE
))
262 // FIXME: optionally return the subkey node/handle as optimization
268 _Inout_ ULONG
* NameSize
)
270 PHHIVE Hive
= &CmHive
->Hive
;
271 PCM_KEY_NODE KeyNode
, SubKeyNode
;
272 PCM_KEY_INDEX IndexCell
;
273 PCM_KEY_FAST_INDEX HashCell
;
274 TRACE("RegEnumKey(%p, %lu, %p, %p->%u)\n",
275 Key
, Index
, Name
, NameSize
, NameSize
? *NameSize
: 0);
277 /* Get the key node */
278 KeyNode
= (PCM_KEY_NODE
)Key
;
279 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
281 /* Check if the index is valid */
282 if ((KeyNode
->SubKeyCounts
[Stable
] == 0) ||
283 (Index
>= KeyNode
->SubKeyCounts
[Stable
]))
285 TRACE("RegEnumKey index out of bounds\n");
286 return ERROR_NO_MORE_ITEMS
;
289 /* Get the index cell */
290 IndexCell
= HvGetCell(Hive
, KeyNode
->SubKeyLists
[Stable
]);
291 TRACE("IndexCell: %x, SubKeyCounts: %x\n", IndexCell
, KeyNode
->SubKeyCounts
[Stable
]);
293 /* Check the cell type */
294 if ((IndexCell
->Signature
== CM_KEY_FAST_LEAF
) ||
295 (IndexCell
->Signature
== CM_KEY_HASH_LEAF
))
297 /* Get the value cell */
298 HashCell
= (PCM_KEY_FAST_INDEX
)IndexCell
;
299 SubKeyNode
= HvGetCell(Hive
, HashCell
->List
[Index
].Cell
);
306 *NameSize
= CmCopyKeyName(SubKeyNode
, Name
, *NameSize
);
308 TRACE("RegEnumKey done -> %u, '%.*s'\n", *NameSize
, *NameSize
, Name
);
309 return STATUS_SUCCESS
;
314 _In_ FRLDRHKEY ParentKey
,
315 _In_z_ PCWSTR KeyName
,
316 _Out_ PFRLDRHKEY Key
)
318 UNICODE_STRING RemainingPath
, SubKeyName
;
319 UNICODE_STRING CurrentControlSet
= RTL_CONSTANT_STRING(L
"CurrentControlSet");
320 PHHIVE Hive
= &CmHive
->Hive
;
321 PCM_KEY_NODE KeyNode
;
322 PCM_KEY_INDEX IndexCell
;
323 TRACE("RegOpenKey(%p, '%S', %p)\n", ParentKey
, KeyName
, Key
);
325 /* Initialize the remaining path name */
326 RtlInitUnicodeString(&RemainingPath
, KeyName
);
328 /* Get the parent key node */
329 KeyNode
= (PCM_KEY_NODE
)ParentKey
;
331 /* Check if we have a parent key */
334 UNICODE_STRING SubKeyName1
, SubKeyName2
, SubKeyName3
;
335 UNICODE_STRING RegistryPath
= RTL_CONSTANT_STRING(L
"Registry");
336 UNICODE_STRING MachinePath
= RTL_CONSTANT_STRING(L
"MACHINE");
337 UNICODE_STRING SystemPath
= RTL_CONSTANT_STRING(L
"SYSTEM");
338 TRACE("RegOpenKey: absolute path\n");
340 if ((RemainingPath
.Length
< sizeof(WCHAR
)) ||
341 RemainingPath
.Buffer
[0] != '\\')
343 /* The key path is not absolute */
344 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName
, &RemainingPath
);
345 return ERROR_PATH_NOT_FOUND
;
348 /* Skip initial path separator */
349 RemainingPath
.Buffer
++;
350 RemainingPath
.Length
-= sizeof(WCHAR
);
352 /* Get the first 3 path elements */
353 GetNextPathElement(&SubKeyName1
, &RemainingPath
);
354 GetNextPathElement(&SubKeyName2
, &RemainingPath
);
355 GetNextPathElement(&SubKeyName3
, &RemainingPath
);
356 TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1
, &SubKeyName2
, &SubKeyName3
);
358 /* Check if we have the correct path */
359 if (!RtlEqualUnicodeString(&SubKeyName1
, &RegistryPath
, TRUE
) ||
360 !RtlEqualUnicodeString(&SubKeyName2
, &MachinePath
, TRUE
) ||
361 !RtlEqualUnicodeString(&SubKeyName3
, &SystemPath
, TRUE
))
363 /* The key path is not inside HKLM\Machine\System */
364 ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName
, &RemainingPath
);
365 return ERROR_PATH_NOT_FOUND
;
368 /* Use the root key */
369 KeyNode
= RootKeyNode
;
372 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
374 /* Check if this is the root key */
375 if (KeyNode
== RootKeyNode
)
377 UNICODE_STRING TempPath
= RemainingPath
;
379 /* Get the first path element */
380 GetNextPathElement(&SubKeyName
, &TempPath
);
382 /* Check if this is CurrentControlSet */
383 if (RtlEqualUnicodeString(&SubKeyName
, &CurrentControlSet
, TRUE
))
385 /* Use the CurrentControlSetKey and update the remaining path */
386 KeyNode
= (PCM_KEY_NODE
)CurrentControlSetKey
;
387 RemainingPath
= TempPath
;
391 TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath
);
393 /* Loop while there are path elements */
394 while (GetNextPathElement(&SubKeyName
, &RemainingPath
))
396 TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName
);
398 /* Check if there is any subkey */
399 if (KeyNode
->SubKeyCounts
[Stable
] == 0)
401 return ERROR_PATH_NOT_FOUND
;
404 /* Get the top level index cell */
405 IndexCell
= HvGetCell(Hive
, KeyNode
->SubKeyLists
[Stable
]);
407 /* Get the next sub key */
408 KeyNode
= RegpFindSubkeyInIndex(Hive
, IndexCell
, &SubKeyName
);
412 ERR("Did not find sub key '%wZ' (full %S)\n", &RemainingPath
, KeyName
);
413 return ERROR_PATH_NOT_FOUND
;
417 TRACE("RegOpenKey done\n");
418 *Key
= (FRLDRHKEY
)KeyNode
;
419 return ERROR_SUCCESS
;
426 _In_ PCM_KEY_VALUE ValueCell
,
427 _Out_opt_ ULONG
* Type
,
428 _Out_opt_ PUCHAR Data
,
429 _Inout_opt_ ULONG
* DataSize
)
433 /* Does the caller want the type? */
436 *Type
= ValueCell
->Type
;
439 /* Does the caller provide DataSize? */
440 if (DataSize
!= NULL
)
442 /* Get the data length */
443 DataLength
= ValueCell
->DataLength
& REG_DATA_SIZE_MASK
;
445 /* Does the caller want the data? */
446 if ((Data
!= NULL
) && (*DataSize
!= 0))
448 /* Check where the data is stored */
449 if ((DataLength
<= sizeof(HCELL_INDEX
)) &&
450 (ValueCell
->DataLength
& REG_DATA_IN_OFFSET
))
452 /* The data member contains the data */
455 min(*DataSize
, DataLength
));
459 /* The data member contains the data cell index */
460 PVOID DataCell
= HvGetCell(Hive
, ValueCell
->Data
);
463 min(*DataSize
, ValueCell
->DataLength
));
468 /* Return the actual data length */
469 *DataSize
= DataLength
;
476 _In_z_ PCWSTR ValueName
,
477 _Out_opt_ ULONG
* Type
,
478 _Out_opt_ PUCHAR Data
,
479 _Inout_opt_ ULONG
* DataSize
)
481 PHHIVE Hive
= &CmHive
->Hive
;
482 PCM_KEY_NODE KeyNode
;
483 PCM_KEY_VALUE ValueCell
;
484 PVALUE_LIST_CELL ValueListCell
;
485 UNICODE_STRING ValueNameString
;
487 TRACE("RegQueryValue(%p, '%S', %p, %p, %p)\n",
488 Key
, ValueName
, Type
, Data
, DataSize
);
490 /* Get the key node */
491 KeyNode
= (PCM_KEY_NODE
)Key
;
492 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
494 /* Check if there are any values */
495 if (KeyNode
->ValueList
.Count
== 0)
497 TRACE("RegQueryValue no values in key (%.*s)\n",
498 KeyNode
->NameLength
, KeyNode
->Name
);
499 return ERROR_INVALID_PARAMETER
;
502 /* Initialize value name string */
503 RtlInitUnicodeString(&ValueNameString
, ValueName
);
505 ValueListCell
= (PVALUE_LIST_CELL
)HvGetCell(Hive
, KeyNode
->ValueList
.List
);
506 TRACE("ValueListCell: %x\n", ValueListCell
);
508 /* Loop all values */
509 for (i
= 0; i
< KeyNode
->ValueList
.Count
; i
++)
511 /* Get the subkey node and check the name */
512 ValueCell
= HvGetCell(Hive
, ValueListCell
->ValueOffset
[i
]);
514 /* Compare the value name */
515 TRACE("checking %.*s\n", ValueCell
->NameLength
, ValueCell
->Name
);
516 if (CmCompareKeyValueName(ValueCell
, &ValueNameString
, TRUE
))
518 RepGetValueData(Hive
, ValueCell
, Type
, Data
, DataSize
);
519 TRACE("RegQueryValue success\n");
520 return STATUS_SUCCESS
;
524 TRACE("RegQueryValue value not found\n");
525 return ERROR_INVALID_PARAMETER
;
533 _Out_ PWCHAR ValueName
,
534 _Inout_ ULONG
* NameSize
,
537 _Inout_ ULONG
* DataSize
)
539 PHHIVE Hive
= &CmHive
->Hive
;
540 PCM_KEY_NODE KeyNode
;
541 PCM_KEY_VALUE ValueCell
;
542 PVALUE_LIST_CELL ValueListCell
;
543 TRACE("RegEnumValue(%p, %lu, %S, %p, %p, %p, %p (%lu))\n",
544 Key
, Index
, ValueName
, NameSize
, Type
, Data
, DataSize
, *DataSize
);
546 /* Get the key node */
547 KeyNode
= (PCM_KEY_NODE
)Key
;
548 ASSERT(KeyNode
->Signature
== CM_KEY_NODE_SIGNATURE
);
550 /* Check if the index is valid */
551 if ((KeyNode
->ValueList
.Count
== 0) ||
552 (Index
>= KeyNode
->ValueList
.Count
))
554 ERR("RegEnumValue: index invalid\n");
555 return ERROR_NO_MORE_ITEMS
;
558 ValueListCell
= (PVALUE_LIST_CELL
)HvGetCell(Hive
, KeyNode
->ValueList
.List
);
559 TRACE("ValueListCell: %x\n", ValueListCell
);
561 /* Get the value cell */
562 ValueCell
= HvGetCell(Hive
, ValueListCell
->ValueOffset
[Index
]);
563 ASSERT(ValueCell
!= NULL
);
565 if (NameSize
!= NULL
)
567 *NameSize
= CmCopyKeyValueName(ValueCell
, ValueName
, *NameSize
);
570 RepGetValueData(Hive
, ValueCell
, Type
, Data
, DataSize
);
572 if (DataSize
!= NULL
)
574 if ((Data
!= NULL
) && (*DataSize
!= 0))
578 min(*DataSize
, ValueCell
->DataLength
));
581 *DataSize
= ValueCell
->DataLength
;
584 TRACE("RegEnumValue done\n");
585 return STATUS_SUCCESS
;