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 PMEMKEY 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 */
50 CMHIVE BcdHive
; /* \Registry\Machine\BCD00000000 */
53 CreateInMemoryStructure(
54 IN PCMHIVE RegistryHive
,
55 IN HCELL_INDEX KeyCellOffset
)
59 Key
= (PMEMKEY
) malloc (sizeof(MEMKEY
));
63 Key
->RegistryHive
= RegistryHive
;
64 Key
->KeyCellOffset
= KeyCellOffset
;
68 LIST_ENTRY CmiReparsePointsHead
;
74 IN BOOL AllowCreation
,
80 UNICODE_STRING KeyString
;
82 PREPARSE_POINT CurrentReparsePoint
;
84 PCMHIVE ParentRegistryHive
;
85 HCELL_INDEX ParentCellOffset
;
87 PCM_KEY_NODE SubKeyCell
;
88 HCELL_INDEX BlockOffset
;
90 DPRINT("RegpCreateOpenKey('%S')\n", KeyName
);
92 if (*KeyName
== L
'\\')
95 ParentRegistryHive
= RootKey
->RegistryHive
;
96 ParentCellOffset
= RootKey
->KeyCellOffset
;
98 else if (hParentKey
== NULL
)
100 ParentRegistryHive
= RootKey
->RegistryHive
;
101 ParentCellOffset
= RootKey
->KeyCellOffset
;
105 ParentRegistryHive
= HKEY_TO_MEMKEY(RootKey
)->RegistryHive
;
106 ParentCellOffset
= HKEY_TO_MEMKEY(RootKey
)->KeyCellOffset
;
109 LocalKeyName
= (PWSTR
)KeyName
;
112 End
= (PWSTR
)strchrW(LocalKeyName
, '\\');
115 KeyString
.Buffer
= LocalKeyName
;
116 KeyString
.Length
= KeyString
.MaximumLength
=
117 (USHORT
)((ULONG_PTR
)End
- (ULONG_PTR
)LocalKeyName
);
121 RtlInitUnicodeString(&KeyString
, LocalKeyName
);
122 if (KeyString
.Length
== 0)
124 /* Trailing backslash char; we're done */
129 Status
= CmiScanForSubKey(ParentRegistryHive
,
132 OBJ_CASE_INSENSITIVE
,
135 if (NT_SUCCESS(Status
))
137 /* Search for a possible reparse point */
138 Ptr
= CmiReparsePointsHead
.Flink
;
139 while (Ptr
!= &CmiReparsePointsHead
)
141 CurrentReparsePoint
= CONTAINING_RECORD(Ptr
, REPARSE_POINT
, ListEntry
);
142 if (CurrentReparsePoint
->SourceHive
== ParentRegistryHive
&&
143 CurrentReparsePoint
->SourceKeyCellOffset
== BlockOffset
)
145 ParentRegistryHive
= CurrentReparsePoint
->DestinationHive
;
146 BlockOffset
= CurrentReparsePoint
->DestinationKeyCellOffset
;
152 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
&& AllowCreation
)
154 Status
= CmiAddSubKey(ParentRegistryHive
,
157 Volatile
? REG_OPTION_VOLATILE
: 0,
161 if (!NT_SUCCESS(Status
))
162 return ERROR_UNSUCCESSFUL
;
165 ParentCellOffset
= BlockOffset
;
167 LocalKeyName
= End
+ 1;
172 CurrentKey
= CreateInMemoryStructure(ParentRegistryHive
, ParentCellOffset
);
174 return ERROR_OUTOFMEMORY
;
175 *Key
= MEMKEY_TO_HKEY(CurrentKey
);
177 return ERROR_SUCCESS
;
186 return RegpOpenOrCreateKey(hKey
, lpSubKey
, TRUE
, FALSE
, phkResult
);
191 IN PCSTR MultiByteString
)
194 UNICODE_STRING Destination
;
197 RtlInitAnsiString(&Source
, MultiByteString
);
198 Status
= RtlAnsiStringToUnicodeString(&Destination
, &Source
, TRUE
);
199 if (!NT_SUCCESS(Status
))
201 return Destination
.Buffer
;
209 DPRINT1("FIXME: implement RegDeleteKeyW!\n");
210 return ERROR_SUCCESS
;
218 PWSTR lpSubKeyW
= NULL
;
221 if (lpSubKey
!= NULL
&& strchr(lpSubKey
, '\\') != NULL
)
222 return ERROR_INVALID_PARAMETER
;
226 lpSubKeyW
= MultiByteToWideChar(lpSubKey
);
228 return ERROR_OUTOFMEMORY
;
231 rc
= RegDeleteKeyW(hKey
, lpSubKeyW
);
245 return RegpOpenOrCreateKey(hKey
, lpSubKey
, FALSE
, FALSE
, phkResult
);
253 IN LPWSTR lpClass OPTIONAL
,
255 IN REGSAM samDesired
,
256 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
,
258 OUT LPDWORD lpdwDisposition OPTIONAL
)
260 return RegpOpenOrCreateKey(hKey
,
263 (dwOptions
& REG_OPTION_VOLATILE
) != 0,
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(ParentKey
->RegistryHive
,
301 ParentKey
->KeyCellOffset
,
305 if (AllowCreation
&& Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
307 Status
= CmiAddValueKey(ParentKey
->RegistryHive
,
308 ParentKey
->KeyCellOffset
,
313 if (!NT_SUCCESS(Status
))
314 return ERROR_UNSUCCESSFUL
;
315 return ERROR_SUCCESS
;
321 IN LPCWSTR lpValueName OPTIONAL
,
324 IN
const UCHAR
* lpData
,
327 PMEMKEY Key
, DestKey
;
329 PCM_KEY_VALUE ValueCell
;
330 HCELL_INDEX ValueCellOffset
;
335 if (dwType
== REG_LINK
)
337 /* Special handling of registry links */
338 if (cbData
!= sizeof(PVOID
))
339 return STATUS_INVALID_PARAMETER
;
341 phKey
= (PHKEY
)lpData
;
342 Key
= HKEY_TO_MEMKEY(hKey
);
343 DestKey
= HKEY_TO_MEMKEY(*phKey
);
345 /* Create the link in registry hive (if applicable) */
346 if (Key
->RegistryHive
!= DestKey
->RegistryHive
)
347 return STATUS_SUCCESS
;
348 DPRINT1("Save link to registry\n");
349 return STATUS_NOT_IMPLEMENTED
;
352 if ((cbData
& REG_DATA_SIZE_MASK
) != cbData
)
353 return STATUS_UNSUCCESSFUL
;
355 Key
= HKEY_TO_MEMKEY(hKey
);
357 Status
= RegpOpenOrCreateValue(hKey
, lpValueName
, TRUE
, &ValueCell
, &ValueCellOffset
);
358 if (!NT_SUCCESS(Status
))
359 return ERROR_UNSUCCESSFUL
;
361 /* Get size of the allocated cellule (if any) */
362 if (!(ValueCell
->DataLength
& REG_DATA_IN_OFFSET
) &&
363 (ValueCell
->DataLength
& REG_DATA_SIZE_MASK
) != 0)
365 DataCell
= HvGetCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
367 return ERROR_UNSUCCESSFUL
;
369 DataCellSize
= -HvGetCellSize(&Key
->RegistryHive
->Hive
, DataCell
);
377 if (cbData
<= sizeof(HCELL_INDEX
))
379 /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
380 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
382 HvFreeCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
384 RtlCopyMemory(&ValueCell
->Data
, lpData
, cbData
);
385 ValueCell
->DataLength
= (ULONG
)(cbData
| REG_DATA_IN_OFFSET
);
386 ValueCell
->Type
= dwType
;
387 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCellOffset
, FALSE
);
391 if (cbData
> (SIZE_T
)DataCellSize
)
393 /* New data size is larger than the current, destroy current
394 * data block and allocate a new one. */
395 HCELL_INDEX NewOffset
;
397 DPRINT("ValueCell->DataLength %u\n", ValueCell
->DataLength
);
399 NewOffset
= HvAllocateCell(&Key
->RegistryHive
->Hive
, cbData
, Stable
, HCELL_NIL
);
400 if (NewOffset
== HCELL_NIL
)
402 DPRINT("HvAllocateCell() failed with status 0x%08x\n", Status
);
403 return ERROR_UNSUCCESSFUL
;
407 HvFreeCell(&Key
->RegistryHive
->Hive
, ValueCell
->Data
);
409 ValueCell
->Data
= NewOffset
;
410 DataCell
= (PVOID
)HvGetCell(&Key
->RegistryHive
->Hive
, NewOffset
);
413 /* Copy new contents to cellule */
414 RtlCopyMemory(DataCell
, lpData
, cbData
);
415 ValueCell
->DataLength
= (ULONG
)(cbData
& REG_DATA_SIZE_MASK
);
416 ValueCell
->Type
= dwType
;
417 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCell
->Data
, FALSE
);
418 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, ValueCellOffset
, FALSE
);
421 HvMarkCellDirty(&Key
->RegistryHive
->Hive
, Key
->KeyCellOffset
, FALSE
);
423 DPRINT("Return status 0x%08x\n", Status
);
430 IN LPCWSTR lpValueName
,
431 IN PULONG lpReserved
,
434 OUT PSIZE_T lpcbData
)
436 //ParentKey = HKEY_TO_MEMKEY(RootKey);
437 PCM_KEY_VALUE ValueCell
;
438 HCELL_INDEX ValueCellOffset
;
441 rc
= RegpOpenOrCreateValue(hKey
,
446 if (rc
!= ERROR_SUCCESS
)
449 DPRINT1("RegQueryValueExW(%S) not implemented\n", lpValueName
);
450 /* ValueCell and ValueCellOffset are valid */
452 return ERROR_UNSUCCESSFUL
;
458 IN LPCWSTR lpValueName OPTIONAL
)
460 DPRINT1("RegDeleteValueW() unimplemented\n");
461 return ERROR_UNSUCCESSFUL
;
467 IN PCMHIVE HiveToConnect
,
471 PREPARSE_POINT ReparsePoint
;
475 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(REPARSE_POINT
));
479 Status
= CmiInitializeTempHive(HiveToConnect
);
480 if (!NT_SUCCESS(Status
))
482 DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status
);
488 rc
= RegCreateKeyExW(RootKey
,
497 if (rc
!= ERROR_SUCCESS
)
503 ReparsePoint
->SourceHive
= NewKey
->RegistryHive
;
504 ReparsePoint
->SourceKeyCellOffset
= NewKey
->KeyCellOffset
;
505 NewKey
->RegistryHive
= HiveToConnect
;
506 NewKey
->KeyCellOffset
= HiveToConnect
->Hive
.BaseBlock
->RootCell
;
507 ReparsePoint
->DestinationHive
= NewKey
->RegistryHive
;
508 ReparsePoint
->DestinationKeyCellOffset
= NewKey
->KeyCellOffset
;
509 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
513 LIST_ENTRY CmiHiveListHead
;
516 RegInitializeRegistry(VOID
)
518 UNICODE_STRING RootKeyName
= RTL_CONSTANT_STRING(L
"\\");
520 PMEMKEY ControlSetKey
, CurrentControlSetKey
;
521 PREPARSE_POINT ReparsePoint
;
523 InitializeListHead(&CmiHiveListHead
);
524 InitializeListHead(&CmiReparsePointsHead
);
526 Status
= CmiInitializeTempHive(&RootHive
);
527 if (!NT_SUCCESS(Status
))
529 DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status
);
533 RootKey
= CreateInMemoryStructure(&RootHive
,
534 RootHive
.Hive
.BaseBlock
->RootCell
);
536 /* Create DEFAULT key */
537 ConnectRegistry(NULL
,
539 L
"Registry\\User\\.DEFAULT");
542 ConnectRegistry(NULL
,
544 L
"Registry\\Machine\\SAM");
546 /* Create SECURITY key */
547 ConnectRegistry(NULL
,
549 L
"Registry\\Machine\\SECURITY");
551 /* Create SOFTWARE key */
552 ConnectRegistry(NULL
,
554 L
"Registry\\Machine\\SOFTWARE");
557 ConnectRegistry(NULL
,
559 L
"Registry\\Machine\\BCD00000000");
561 /* Create SYSTEM key */
562 ConnectRegistry(NULL
,
564 L
"Registry\\Machine\\SYSTEM");
566 /* Create 'ControlSet001' key */
568 L
"Registry\\Machine\\SYSTEM\\ControlSet001",
569 (HKEY
*)&ControlSetKey
);
571 /* Create 'CurrentControlSet' key */
572 RegCreateKeyExW(NULL
,
573 L
"Registry\\Machine\\SYSTEM\\CurrentControlSet",
579 (HKEY
*)&CurrentControlSetKey
,
582 /* Connect 'CurrentControlSet' to 'ControlSet001' */
583 ReparsePoint
= (PREPARSE_POINT
)malloc(sizeof(REPARSE_POINT
));
584 ReparsePoint
->SourceHive
= CurrentControlSetKey
->RegistryHive
;
585 ReparsePoint
->SourceKeyCellOffset
= CurrentControlSetKey
->KeyCellOffset
;
586 ReparsePoint
->DestinationHive
= ControlSetKey
->RegistryHive
;
587 ReparsePoint
->DestinationKeyCellOffset
= ControlSetKey
->KeyCellOffset
;
588 InsertTailList(&CmiReparsePointsHead
, &ReparsePoint
->ListEntry
);
592 RegShutdownRegistry(VOID
)
594 /* FIXME: clean up the complete hive */