3 * Copyright (C) 2006 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS hive maker
21 * FILE: tools/mkhive/registry.c
22 * PURPOSE: Registry code
23 * PROGRAMMER: Hervé Poussineau
28 * - Implement RegDeleteKeyW()
29 * - Implement RegEnumValue()
30 * - Implement RegQueryValueExW()
40 #define REG_DATA_SIZE_MASK 0x7FFFFFFF
41 #define REG_DATA_IN_OFFSET 0x80000000
43 static CMHIVE RootHive
;
44 static MEMKEY RootKey
;
45 CMHIVE DefaultHive
; /* \Registry\User\.DEFAULT */
46 CMHIVE SamHive
; /* \Registry\Machine\SAM */
47 CMHIVE SecurityHive
; /* \Registry\Machine\SECURITY */
48 CMHIVE SoftwareHive
; /* \Registry\Machine\SOFTWARE */
49 CMHIVE SystemHive
; /* \Registry\Machine\SYSTEM */
52 CreateInMemoryStructure(
53 IN PCMHIVE RegistryHive
,
54 IN HCELL_INDEX KeyCellOffset
,
55 IN PCUNICODE_STRING KeyName
)
59 Key
= (MEMKEY
) malloc (sizeof(KEY
));
63 InitializeListHead (&Key
->SubKeyList
);
64 InitializeListHead (&Key
->ValueList
);
65 InitializeListHead (&Key
->KeyList
);
74 Key
->RegistryHive
= RegistryHive
;
75 Key
->KeyCellOffset
= Key
->KeyCellOffsetInParentHive
= KeyCellOffset
;
76 Key
->KeyCell
= (PCM_KEY_NODE
)HvGetCell (&RegistryHive
->Hive
, Key
->KeyCellOffset
);
82 Key
->KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
83 Key
->KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
84 Key
->LinkedKey
= NULL
;
92 IN BOOL AllowCreation
,
97 UNICODE_STRING KeyString
;
102 PCM_KEY_NODE SubKeyCell
;
103 HCELL_INDEX BlockOffset
;
104 BOOLEAN ParentIsSystem
= FALSE
;
106 DPRINT("RegpCreateOpenKey('%S')\n", KeyName
);
108 if (*KeyName
== L
'\\')
113 else if (hParentKey
== NULL
)
119 ParentKey
= HKEY_TO_MEMKEY(RootKey
);
122 LocalKeyName
= (PWSTR
)KeyName
;
125 End
= (PWSTR
)strchrW(LocalKeyName
, '\\');
128 KeyString
.Buffer
= LocalKeyName
;
129 KeyString
.Length
= KeyString
.MaximumLength
=
130 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
134 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
135 if (KeyString
.Length
== 0)
137 /* Trailing backslash char; we're done */
142 /* Redirect from 'CurrentControlSet' to 'ControlSet001' */
143 if (!strncmpiW(LocalKeyName
, L
"CurrentControlSet", 17) && ParentIsSystem
)
145 RtlInitUnicodeString(&KeyString
, L
"ControlSet001");
146 ParentIsSystem
= FALSE
;
150 ParentIsSystem
= (strncmpiW(LocalKeyName
, L
"SYSTEM", 6) == 0);
153 Status
= CmiScanForSubKey(
154 ParentKey
->RegistryHive
,
157 OBJ_CASE_INSENSITIVE
,
160 if (NT_SUCCESS(Status
))
162 /* Check subkey in memory structure */
163 Ptr
= ParentKey
->SubKeyList
.Flink
;
164 while (Ptr
!= &ParentKey
->SubKeyList
)
166 CurrentKey
= CONTAINING_RECORD(Ptr
, KEY
, KeyList
);
167 if (CurrentKey
->KeyCellOffsetInParentHive
== BlockOffset
)
174 /* If we go there, this means that key exists, but we don't know it */
178 if (AllowCreation
&& Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
180 Status
= CmiAddSubKey(
181 ParentKey
->RegistryHive
,
183 ParentKey
->KeyCellOffset
,
188 if (NT_SUCCESS(Status
))
190 /* Now, SubKeyCell/BlockOffset are valid */
191 CurrentKey
= CreateInMemoryStructure(
192 ParentKey
->RegistryHive
,
196 return ERROR_OUTOFMEMORY
;
197 /* Add CurrentKey in ParentKey */
198 InsertTailList(&ParentKey
->SubKeyList
, &CurrentKey
->KeyList
);
199 ParentKey
->SubKeyCount
++;
202 if (!NT_SUCCESS(Status
))
203 return ERROR_UNSUCCESSFUL
;
206 ParentKey
= CurrentKey
;
208 LocalKeyName
= End
+ 1;
213 *Key
= MEMKEY_TO_HKEY(ParentKey
);
215 return ERROR_SUCCESS
;
224 return RegpOpenOrCreateKey(hKey
, lpSubKey
, TRUE
, phkResult
);
229 IN PCSTR MultiByteString
)
232 UNICODE_STRING Destination
;
235 RtlInitAnsiString(&Source
, MultiByteString
);
236 Status
= RtlAnsiStringToUnicodeString(&Destination
, &Source
, TRUE
);
237 if (!NT_SUCCESS(Status
))
239 return Destination
.Buffer
;
251 lpSubKeyW
= MultiByteToWideChar(lpSubKey
);
253 return ERROR_OUTOFMEMORY
;
255 rc
= RegCreateKeyW(hKey
, lpSubKeyW
, phkResult
);
265 DPRINT1("FIXME: implement RegDeleteKeyW!\n");
266 return ERROR_SUCCESS
;
274 PWSTR lpSubKeyW
= NULL
;
277 if (lpSubKey
!= NULL
&& strchr(lpSubKey
, '\\') != NULL
)
278 return ERROR_INVALID_PARAMETER
;
282 lpSubKeyW
= MultiByteToWideChar(lpSubKey
);
284 return ERROR_OUTOFMEMORY
;
287 rc
= RegDeleteKeyW(hKey
, lpSubKeyW
);
301 return RegpOpenOrCreateKey(hKey
, lpSubKey
, FALSE
, phkResult
);
313 lpSubKeyW
= MultiByteToWideChar(lpSubKey
);
315 return ERROR_OUTOFMEMORY
;
317 rc
= RegOpenKeyW(hKey
, lpSubKeyW
, phkResult
);
323 RegpOpenOrCreateValue(
325 IN LPCWSTR ValueName
,
326 IN BOOL AllowCreation
,
327 OUT PCM_KEY_VALUE
*ValueCell
,
328 OUT PHCELL_INDEX ValueCellOffset
)
331 UNICODE_STRING ValueString
;
334 ParentKey
= HKEY_TO_MEMKEY(hKey
);
335 RtlInitUnicodeString(&ValueString
, ValueName
);
337 Status
= CmiScanForValueKey(
338 ParentKey
->RegistryHive
,
343 if (AllowCreation
&& Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
345 Status
= CmiAddValueKey(
346 ParentKey
->RegistryHive
,
348 ParentKey
->KeyCellOffset
,
353 if (!NT_SUCCESS(Status
))
354 return ERROR_UNSUCCESSFUL
;
355 return ERROR_SUCCESS
;
361 IN LPCWSTR lpValueName OPTIONAL
,
364 IN
const UCHAR
* lpData
,
369 PCM_KEY_VALUE ValueCell
;
370 HCELL_INDEX ValueCellOffset
;
375 if (dwType
== REG_LINK
)
377 /* Special handling of registry links */
378 if (cbData
!= sizeof(PVOID
))
379 return STATUS_INVALID_PARAMETER
;
380 phKey
= (PHKEY
)lpData
;
381 Key
= HKEY_TO_MEMKEY(hKey
);
382 DestKey
= HKEY_TO_MEMKEY(*phKey
);
384 /* Create the link in memory */
385 Key
->DataType
= REG_LINK
;
386 Key
->LinkedKey
= DestKey
;
388 /* Create the link in registry hive (if applicable) */
389 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
390 return STATUS_SUCCESS
;
391 DPRINT1("Save link to registry\n");
392 return STATUS_NOT_IMPLEMENTED
;
395 if ((cbData
& REG_DATA_SIZE_MASK
) != cbData
)
396 return STATUS_UNSUCCESSFUL
;
398 Key
= HKEY_TO_MEMKEY(hKey
);
400 Status
= RegpOpenOrCreateValue(hKey
, lpValueName
, TRUE
, &ValueCell
, &ValueCellOffset
);
401 if (!NT_SUCCESS(Status
))
402 return ERROR_UNSUCCESSFUL
;
404 /* Get size of the allocated cellule (if any) */
405 if (!(ValueCell
->DataLength
& REG_DATA_IN_OFFSET
) &&
406 (ValueCell
->DataLength
& REG_DATA_SIZE_MASK
) != 0)
408 DataCell
= HvGetCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
410 return ERROR_UNSUCCESSFUL
;
411 DataCellSize
= -HvGetCellSize(&Key
->RegistryHive
->Hive
, DataCell
);
419 if (cbData
<= sizeof(HCELL_INDEX
))
421 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
422 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
424 HvFreeCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
426 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
427 ValueCell
->DataLength
= (ULONG
)(cbData
| REG_DATA_IN_OFFSET
);
428 ValueCell
->Type
= dwType
;
429 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCellOffset
, FALSE
);
433 if (cbData
> (SIZE_T
)DataCellSize
)
435 /* New data size is larger than the current, destroy current
436 * data block and allocate a new one. */
437 HCELL_INDEX NewOffset
;
439 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
441 NewOffset
= HvAllocateCell(&Key
->RegistryHive
->Hive
, cbData
, Stable
, HCELL_NIL
);
442 if (NewOffset
== HCELL_NIL
)
444 DPRINT("HvAllocateCell() failed with status 0x%08x\n", Status
);
445 return ERROR_UNSUCCESSFUL
;
449 HvFreeCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
451 ValueCell
->Data
= NewOffset
;
452 DataCell
= (PVOID
)HvGetCell(&Key
->RegistryHive
->Hive
, NewOffset
);
455 /* Copy new contents to cellule */
456 RtlCopyMemory(DataCell
, lpData
, cbData
);
457 ValueCell
->DataLength
= (ULONG
)(cbData
& REG_DATA_SIZE_MASK
);
458 ValueCell
->Type
= dwType
;
459 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCell
->Data
, FALSE
);
460 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCellOffset
, FALSE
);
463 if (cbData
> Key
->KeyCell
->MaxValueDataLen
)
464 Key
->KeyCell
->MaxValueDataLen
= cbData
;
466 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, Key
->KeyCellOffset
, FALSE
);
468 DPRINT("Return status 0x%08x\n", Status
);
475 IN LPCSTR lpValueName OPTIONAL
,
478 IN
const UCHAR
* lpData
,
481 LPWSTR lpValueNameW
= NULL
;
482 const UCHAR
* lpDataW
;
484 LONG rc
= ERROR_SUCCESS
;
486 DPRINT("RegSetValueA(%s)\n", lpValueName
);
489 lpValueNameW
= MultiByteToWideChar(lpValueName
);
491 return ERROR_OUTOFMEMORY
;
494 if ((dwType
== REG_SZ
|| dwType
== REG_EXPAND_SZ
|| dwType
== REG_MULTI_SZ
)
497 ANSI_STRING AnsiString
;
500 if (lpData
[cbData
- 1] != '\0')
502 RtlInitAnsiString(&AnsiString
, NULL
);
503 AnsiString
.Buffer
= (PSTR
)lpData
;
504 AnsiString
.Length
= (USHORT
)cbData
- 1;
505 AnsiString
.MaximumLength
= (USHORT
)cbData
;
506 RtlAnsiStringToUnicodeString (&Data
, &AnsiString
, TRUE
);
507 lpDataW
= (const UCHAR
*)Data
.Buffer
;
508 cbDataW
= Data
.MaximumLength
;
513 cbDataW
= (USHORT
)cbData
;
516 if (rc
== ERROR_SUCCESS
)
517 rc
= RegSetValueExW(hKey
, lpValueNameW
, 0, dwType
, lpDataW
, cbDataW
);
520 if (lpData
!= lpDataW
)
521 free((PVOID
)lpDataW
);
528 IN LPCWSTR lpValueName
,
529 IN PULONG lpReserved
,
532 OUT PSIZE_T lpcbData
)
534 //ParentKey = HKEY_TO_MEMKEY(RootKey);
535 PCM_KEY_VALUE ValueCell
;
536 HCELL_INDEX ValueCellOffset
;
539 rc
= RegpOpenOrCreateValue(
545 if (rc
!= ERROR_SUCCESS
)
548 DPRINT1("RegQueryValueExW(%S) not implemented\n", lpValueName
);
549 /* ValueCell and ValueCellOffset are valid */
551 return ERROR_UNSUCCESSFUL
;
557 IN LPCSTR lpValueName
,
558 IN PULONG lpReserved
,
561 OUT PSIZE_T lpcbData
)
563 LPWSTR lpValueNameW
= NULL
;
568 lpValueNameW
= MultiByteToWideChar(lpValueName
);
570 return ERROR_OUTOFMEMORY
;
573 rc
= RegQueryValueExW(hKey
, lpValueNameW
, lpReserved
, lpType
, lpData
, lpcbData
);
582 IN LPCWSTR lpValueName OPTIONAL
)
584 DPRINT1("RegDeleteValueW() unimplemented\n");
585 return ERROR_UNSUCCESSFUL
;
591 IN LPCSTR lpValueName OPTIONAL
)
598 lpValueNameW
= MultiByteToWideChar(lpValueName
);
600 return ERROR_OUTOFMEMORY
;
601 rc
= RegDeleteValueW(hKey
, lpValueNameW
);
605 rc
= RegDeleteValueW(hKey
, NULL
);
612 IN PCMHIVE HiveToConnect
,
619 Status
= CmiInitializeTempHive(HiveToConnect
);
620 if (!NT_SUCCESS(Status
))
622 DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status
);
631 if (rc
!= ERROR_SUCCESS
)
634 NewKey
->RegistryHive
= HiveToConnect
;
635 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
636 NewKey
->KeyCell
= (PCM_KEY_NODE
)HvGetCell (&HiveToConnect
->Hive
, NewKey
->KeyCellOffset
);
640 LIST_ENTRY CmiHiveListHead
;
643 RegInitializeRegistry(VOID
)
645 UNICODE_STRING RootKeyName
= RTL_CONSTANT_STRING(L
"\\");
649 InitializeListHead(&CmiHiveListHead
);
651 Status
= CmiInitializeTempHive(&RootHive
);
652 if (!NT_SUCCESS(Status
))
654 DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status
);
658 RootKey
= CreateInMemoryStructure(
660 RootHive
.Hive
.BaseBlock
->RootCell
,
663 /* Create DEFAULT key */
667 L
"Registry\\User\\.DEFAULT");
673 L
"Registry\\Machine\\SAM");
675 /* Create SECURITY key */
679 L
"Registry\\Machine\\SECURITY");
681 /* Create SOFTWARE key */
685 L
"Registry\\Machine\\SOFTWARE");
687 /* Create SYSTEM key */
691 L
"Registry\\Machine\\SYSTEM");
693 /* Create 'ControlSet001' key */
696 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
701 RegShutdownRegistry(VOID
)
703 /* FIXME: clean up the complete hive */