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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 RegDeleteKey()
29 * - Implement RegEnumValue()
30 * - Implement RegQueryValueExA()
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
);
70 Key
->NameSize
= KeyName
->Length
;
71 Key
->Name
= malloc (Key
->NameSize
);
74 memcpy(Key
->Name
, KeyName
->Buffer
, KeyName
->Length
);
80 Key
->RegistryHive
= RegistryHive
;
81 Key
->KeyCellOffset
= KeyCellOffset
;
82 Key
->KeyCell
= (PCM_KEY_NODE
)HvGetCell (&RegistryHive
->Hive
, Key
->KeyCellOffset
);
88 Key
->LinkedKey
= NULL
;
96 IN BOOL AllowCreation
,
101 UNICODE_STRING KeyString
;
106 PCM_KEY_NODE SubKeyCell
;
107 HCELL_INDEX BlockOffset
;
109 DPRINT("RegpCreateOpenKey('%S')\n", KeyName
);
111 if (*KeyName
== L
'\\')
116 else if (hParentKey
== NULL
)
122 ParentKey
= HKEY_TO_MEMKEY(RootKey
);
125 LocalKeyName
= (PWSTR
)KeyName
;
128 End
= (PWSTR
) xwcschr(LocalKeyName
, '\\');
131 KeyString
.Buffer
= LocalKeyName
;
132 KeyString
.Length
= KeyString
.MaximumLength
=
133 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
136 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
138 /* Redirect from 'CurrentControlSet' to 'ControlSet001' */
139 if (!memcmp(LocalKeyName
, L
"CurrentControlSet", 34) &&
140 ParentKey
->NameSize
== 12 &&
141 !memcmp(ParentKey
->Name
, L
"SYSTEM", 12))
142 RtlInitUnicodeString(&KeyString
, L
"ControlSet001");
144 /* Check subkey in memory structure */
145 Ptr
= ParentKey
->SubKeyList
.Flink
;
146 while (Ptr
!= &ParentKey
->SubKeyList
)
148 CurrentKey
= CONTAINING_RECORD(Ptr
, KEY
, KeyList
);
149 if (CurrentKey
->NameSize
== KeyString
.Length
150 && memcmp(CurrentKey
->Name
, KeyString
.Buffer
, KeyString
.Length
) == 0)
158 Status
= CmiScanForSubKey(
159 ParentKey
->RegistryHive
,
162 OBJ_CASE_INSENSITIVE
,
165 if (AllowCreation
&& Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
167 Status
= CmiAddSubKey(
168 ParentKey
->RegistryHive
,
170 ParentKey
->KeyCellOffset
,
176 if (!NT_SUCCESS(Status
))
177 return ERROR_UNSUCCESSFUL
;
179 /* Now, SubKeyCell/BlockOffset are valid */
180 CurrentKey
= CreateInMemoryStructure(
181 ParentKey
->RegistryHive
,
185 return ERROR_OUTOFMEMORY
;
187 /* Add CurrentKey in ParentKey */
188 InsertTailList(&ParentKey
->SubKeyList
, &CurrentKey
->KeyList
);
189 ParentKey
->SubKeyCount
++;
192 ParentKey
= CurrentKey
;
194 LocalKeyName
= End
+ 1;
199 *Key
= MEMKEY_TO_HKEY(ParentKey
);
201 return ERROR_SUCCESS
;
210 return RegpOpenOrCreateKey(hKey
, lpSubKey
, TRUE
, phkResult
);
215 IN PCSTR MultiByteString
)
218 UNICODE_STRING Destination
;
221 RtlInitAnsiString(&Source
, MultiByteString
);
222 Status
= RtlAnsiStringToUnicodeString(&Destination
, &Source
, TRUE
);
223 if (!NT_SUCCESS(Status
))
225 return Destination
.Buffer
;
237 lpSubKeyW
= MultiByteToWideChar(lpSubKey
);
239 return ERROR_OUTOFMEMORY
;
241 rc
= RegCreateKeyW(hKey
, lpSubKeyW
, phkResult
);
247 RegDeleteKeyA(HKEY Key
,
250 if (Name
!= NULL
&& strchr(Name
, '\\') != NULL
)
251 return(ERROR_INVALID_PARAMETER
);
255 return(ERROR_SUCCESS
);
264 return RegpOpenOrCreateKey(hKey
, lpSubKey
, FALSE
, phkResult
);
276 lpSubKeyW
= MultiByteToWideChar(lpSubKey
);
278 return ERROR_OUTOFMEMORY
;
280 rc
= RegOpenKeyW(hKey
, lpSubKeyW
, phkResult
);
286 RegpOpenOrCreateValue(
288 IN LPCWSTR ValueName
,
289 IN BOOL AllowCreation
,
290 OUT PCM_KEY_VALUE
*ValueCell
,
291 OUT PHCELL_INDEX ValueCellOffset
)
294 UNICODE_STRING ValueString
;
297 ParentKey
= HKEY_TO_MEMKEY(hKey
);
298 RtlInitUnicodeString(&ValueString
, ValueName
);
300 Status
= CmiScanForValueKey(
301 ParentKey
->RegistryHive
,
306 if (AllowCreation
&& Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
308 Status
= CmiAddValueKey(
309 ParentKey
->RegistryHive
,
311 ParentKey
->KeyCellOffset
,
316 if (!NT_SUCCESS(Status
))
317 return ERROR_UNSUCCESSFUL
;
318 return ERROR_SUCCESS
;
324 IN LPCWSTR lpValueName OPTIONAL
,
327 IN
const UCHAR
* lpData
,
332 PCM_KEY_VALUE ValueCell
;
333 HCELL_INDEX ValueCellOffset
;
338 if (dwType
== REG_LINK
)
340 /* Special handling of registry links */
341 if (cbData
!= sizeof(PVOID
))
342 return STATUS_INVALID_PARAMETER
;
343 phKey
= (PHKEY
)lpData
;
344 Key
= HKEY_TO_MEMKEY(hKey
);
345 DestKey
= HKEY_TO_MEMKEY(*phKey
);
347 /* Create the link in memory */
348 Key
->DataType
= REG_LINK
;
349 Key
->LinkedKey
= DestKey
;
351 /* Create the link in registry hive (if applicable) */
352 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
353 return STATUS_SUCCESS
;
354 DPRINT1("Save link to registry\n");
355 return STATUS_NOT_IMPLEMENTED
;
358 if ((cbData
& REG_DATA_SIZE_MASK
) != cbData
)
359 return STATUS_UNSUCCESSFUL
;
361 Key
= HKEY_TO_MEMKEY(hKey
);
363 Status
= RegpOpenOrCreateValue(hKey
, lpValueName
, TRUE
, &ValueCell
, &ValueCellOffset
);
364 if (!NT_SUCCESS(Status
))
365 return ERROR_UNSUCCESSFUL
;
367 /* Get size of the allocated cellule (if any) */
368 if (!(ValueCell
->DataLength
& REG_DATA_IN_OFFSET
) &&
369 (ValueCell
->DataLength
& REG_DATA_SIZE_MASK
) != 0)
371 DataCell
= HvGetCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
373 return ERROR_UNSUCCESSFUL
;
374 DataCellSize
= -HvGetCellSize(&Key
->RegistryHive
->Hive
, DataCell
);
382 if (cbData
<= sizeof(HCELL_INDEX
))
384 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
385 DPRINT("ValueCell->DataLength %lu\n", ValueCell
->DataLength
);
387 HvFreeCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
389 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
390 ValueCell
->DataLength
= (ULONG
)(cbData
| REG_DATA_IN_OFFSET
);
391 ValueCell
->Type
= dwType
;
392 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCellOffset
, FALSE
);
396 if (cbData
> (SIZE_T
)DataCellSize
)
398 /* New data size is larger than the current, destroy current
399 * data block and allocate a new one. */
400 HCELL_INDEX NewOffset
;
402 DPRINT("ValueCell->DataLength %lu\n", ValueCell
->DataLength
);
404 NewOffset
= HvAllocateCell(&Key
->RegistryHive
->Hive
, cbData
, Stable
, HCELL_NIL
);
405 if (NewOffset
== HCELL_NIL
)
407 DPRINT("HvAllocateCell() failed with status 0x%08lx\n", Status
);
408 return ERROR_UNSUCCESSFUL
;
412 HvFreeCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
414 ValueCell
->Data
= NewOffset
;
415 DataCell
= (PVOID
)HvGetCell(&Key
->RegistryHive
->Hive
, NewOffset
);
418 /* Copy new contents to cellule */
419 RtlCopyMemory(DataCell
, lpData
, cbData
);
420 ValueCell
->DataLength
= (ULONG
)(cbData
& REG_DATA_SIZE_MASK
);
421 ValueCell
->Type
= dwType
;
422 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCell
->Data
, FALSE
);
423 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCellOffset
, FALSE
);
426 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, Key
->KeyCellOffset
, FALSE
);
428 DPRINT("Return status 0x%08lx\n", Status
);
435 IN LPCSTR lpValueName OPTIONAL
,
438 IN
const UCHAR
* lpData
,
441 LPWSTR lpValueNameW
= NULL
;
442 const UCHAR
* lpDataW
;
444 LONG rc
= ERROR_SUCCESS
;
446 DPRINT("RegSetValueA(%s)\n", lpValueName
);
449 lpValueNameW
= MultiByteToWideChar(lpValueName
);
451 return ERROR_OUTOFMEMORY
;
454 if ((dwType
== REG_SZ
|| dwType
== REG_EXPAND_SZ
|| dwType
== REG_MULTI_SZ
)
457 ANSI_STRING AnsiString
;
460 if (lpData
[cbData
- 1] != '\0')
462 RtlInitAnsiString(&AnsiString
, NULL
);
463 AnsiString
.Buffer
= (PSTR
)lpData
;
464 AnsiString
.Length
= (USHORT
)cbData
- 1;
465 AnsiString
.MaximumLength
= (USHORT
)cbData
;
466 RtlAnsiStringToUnicodeString (&Data
, &AnsiString
, TRUE
);
467 lpDataW
= (const UCHAR
*)Data
.Buffer
;
468 cbDataW
= Data
.MaximumLength
;
473 cbDataW
= (USHORT
)cbData
;
476 if (rc
== ERROR_SUCCESS
)
477 rc
= RegSetValueExW(hKey
, lpValueNameW
, 0, dwType
, lpDataW
, cbDataW
);
480 if (lpData
!= lpDataW
)
481 free((PVOID
)lpDataW
);
488 IN LPCWSTR lpValueName
,
489 IN PULONG lpReserved
,
492 OUT PSIZE_T lpcbData
)
494 //ParentKey = HKEY_TO_MEMKEY(RootKey);
495 PCM_KEY_VALUE ValueCell
;
496 HCELL_INDEX ValueCellOffset
;
499 rc
= RegpOpenOrCreateValue(
505 if (rc
!= ERROR_SUCCESS
)
508 DPRINT1("RegQueryValueExW(%S) not implemented\n", lpValueName
);
509 /* ValueCell and ValueCellOffset are valid */
511 return ERROR_UNSUCCESSFUL
;
517 IN LPCSTR lpValueName
,
518 IN PULONG lpReserved
,
521 OUT PSIZE_T lpcbData
)
523 LPWSTR lpValueNameW
= NULL
;
528 lpValueNameW
= MultiByteToWideChar(lpValueName
);
530 return ERROR_OUTOFMEMORY
;
533 rc
= RegQueryValueExW(hKey
, lpValueNameW
, lpReserved
, lpType
, lpData
, lpcbData
);
536 return ERROR_UNSUCCESSFUL
;
542 IN LPCWSTR lpValueName OPTIONAL
)
544 DPRINT1("RegDeleteValueW() unimplemented\n");
545 return ERROR_UNSUCCESSFUL
;
551 IN LPCSTR lpValueName OPTIONAL
)
558 lpValueNameW
= MultiByteToWideChar(lpValueName
);
560 return ERROR_OUTOFMEMORY
;
561 rc
= RegDeleteValueW(hKey
, lpValueNameW
);
565 rc
= RegDeleteValueW(hKey
, NULL
);
572 IN PCMHIVE HiveToConnect
,
579 Status
= CmiInitializeTempHive(HiveToConnect
);
580 if (!NT_SUCCESS(Status
))
582 DPRINT1("CmiInitializeTempHive() failed with status 0x%08lx\n", Status
);
591 if (rc
!= ERROR_SUCCESS
)
594 NewKey
->RegistryHive
= HiveToConnect
;
595 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
596 NewKey
->KeyCell
= (PCM_KEY_NODE
)HvGetCell (&HiveToConnect
->Hive
, NewKey
->KeyCellOffset
);
601 MyExportBinaryHive (PCHAR FileName
,
607 /* Create new hive file */
608 File
= fopen (FileName
, "w+b");
611 printf(" Error creating/opening file\n");
615 fseek (File
, 0, SEEK_SET
);
617 RootHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = (HANDLE
)File
;
618 ret
= HvWriteHive(&RootHive
->Hive
);
623 LIST_ENTRY CmiHiveListHead
;
626 RegInitializeRegistry(VOID
)
628 UNICODE_STRING RootKeyName
= RTL_CONSTANT_STRING(L
"\\");
632 InitializeListHead(&CmiHiveListHead
);
634 Status
= CmiInitializeTempHive(&RootHive
);
635 if (!NT_SUCCESS(Status
))
637 DPRINT1("CmiInitializeTempHive() failed with status 0x%08lx\n", Status
);
641 RootKey
= CreateInMemoryStructure(
643 RootHive
.Hive
.BaseBlock
->RootCell
,
646 /* Create DEFAULT key */
650 L
"Registry\\User\\.DEFAULT");
656 L
"Registry\\Machine\\SAM");
658 /* Create SECURITY key */
662 L
"Registry\\Machine\\SECURITY");
664 /* Create SOFTWARE key */
668 L
"Registry\\Machine\\SOFTWARE");
670 /* Create SYSTEM key */
674 L
"Registry\\Machine\\SYSTEM");
676 /* Create 'ControlSet001' key */
679 L
"Registry\\Machine\\SYSTEM\\ControlSet001",