3 * Copyright (C) 2003 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.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Setup Library
22 * FILE: base/setup/lib/registry.c
23 * PURPOSE: Registry creation functions
25 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
28 /* INCLUDES *****************************************************************/
45 #if 1 // FIXME: Disable if setupapi.h is included in the code...
46 #define FLG_ADDREG_BINVALUETYPE 0x00000001
47 #define FLG_ADDREG_NOCLOBBER 0x00000002
48 #define FLG_ADDREG_DELVAL 0x00000004
49 #define FLG_ADDREG_APPEND 0x00000008
50 #define FLG_ADDREG_KEYONLY 0x00000010
51 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
52 #define FLG_ADDREG_TYPE_SZ 0x00000000
53 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
54 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
55 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
56 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
57 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
58 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
62 #define Architecture L"x86"
63 #elif defined(_M_AMD64)
64 #define Architecture L"amd64"
65 #elif defined(_M_IA64)
66 #define Architecture L"ia64"
68 #define Architecture L"arm"
70 #define Architecture L"ppc"
73 /* FUNCTIONS ****************************************************************/
75 #define REGISTRY_SETUP_MACHINE L"\\Registry\\Machine\\SYSTEM\\USetup_Machine\\"
76 #define REGISTRY_SETUP_USER L"\\Registry\\Machine\\SYSTEM\\USetup_User\\"
78 typedef struct _ROOT_KEY
83 } ROOT_KEY
, *PROOT_KEY
;
87 { L
"HKCR", REGISTRY_SETUP_MACHINE L
"SOFTWARE\\Classes\\", NULL
}, /* "\\Registry\\Machine\\SOFTWARE\\Classes\\" */ // HKEY_CLASSES_ROOT
88 { L
"HKCU", REGISTRY_SETUP_USER L
".DEFAULT\\" , NULL
}, /* "\\Registry\\User\\.DEFAULT\\" */ // HKEY_CURRENT_USER
89 { L
"HKLM", REGISTRY_SETUP_MACHINE
, NULL
}, /* "\\Registry\\Machine\\" */ // HKEY_LOCAL_MACHINE
90 { L
"HKU" , REGISTRY_SETUP_USER
, NULL
}, /* "\\Registry\\User\\" */ // HKEY_USERS
92 { L
"HKR", NULL
, NULL
},
96 #define IsPredefKey(HKey) \
97 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
99 #define GetPredefKeyIndex(HKey) \
100 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
103 GetRootKeyByPredefKey(
105 OUT PCWSTR
* RootKeyMountPoint OPTIONAL
)
107 ULONG_PTR Index
= GetPredefKeyIndex(KeyHandle
);
109 if (!IsPredefKey(KeyHandle
))
111 if (Index
>= ARRAYSIZE(RootKeys
))
114 if (RootKeyMountPoint
)
115 *RootKeyMountPoint
= RootKeys
[Index
].MountPoint
;
116 return RootKeys
[Index
].Handle
;
121 IN PCWSTR RootKeyName
,
122 OUT PCWSTR
* RootKeyMountPoint OPTIONAL
)
126 for (i
= 0; i
< ARRAYSIZE(RootKeys
); ++i
)
128 if (!_wcsicmp(RootKeyName
, RootKeys
[i
].Name
))
130 if (RootKeyMountPoint
)
131 *RootKeyMountPoint
= RootKeys
[i
].MountPoint
;
132 return RootKeys
[i
].Handle
;
140 /***********************************************************************
141 * append_multi_sz_value
143 * Append a multisz string to a multisz registry value.
145 // NOTE: Synced with setupapi/install.c ; see also mkhive/reginf.c
148 append_multi_sz_value (HANDLE hkey
,
150 const WCHAR
*strings
,
153 DWORD size
, type
, total
;
156 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
157 if (type
!= REG_MULTI_SZ
) return;
159 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
+ str_size
* sizeof(WCHAR
) ))) return;
160 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
162 /* compare each string against all the existing ones */
166 int len
= strlenW(strings
) + 1;
168 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
169 if (!strcmpiW( p
, strings
)) break;
171 if (!*p
) /* not found, need to append it */
173 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
181 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
182 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
185 HeapFree( GetProcessHeap(), 0, buffer
);
189 /***********************************************************************
190 * delete_multi_sz_value
192 * Remove a string from a multisz registry value.
195 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
198 WCHAR
*buffer
, *src
, *dst
;
200 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
201 if (type
!= REG_MULTI_SZ
) return;
202 /* allocate double the size, one for value before and one for after */
203 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
204 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
209 int len
= strlenW(src
) + 1;
210 if (strcmpiW( src
, string
))
212 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
218 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
220 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
221 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
222 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
225 HeapFree( GetProcessHeap(), 0, buffer
);
229 /***********************************************************************
232 * Perform an add/delete registry operation depending on the flags.
235 do_reg_operation(HANDLE KeyHandle
,
236 PUNICODE_STRING ValueName
,
244 if (Flags
& FLG_ADDREG_DELVAL
) /* deletion */
249 RegDeleteValueW( KeyHandle
, ValueName
);
253 RegDeleteKeyW( KeyHandle
, NULL
);
259 if (Flags
& FLG_ADDREG_KEYONLY
)
263 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
265 BOOL exists
= !RegQueryValueExW( hkey
, ValueName
, NULL
, NULL
, NULL
, NULL
);
266 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
268 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
273 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
275 case FLG_ADDREG_TYPE_SZ
:
279 case FLG_ADDREG_TYPE_MULTI_SZ
:
283 case FLG_ADDREG_TYPE_EXPAND_SZ
:
284 Type
= REG_EXPAND_SZ
;
287 case FLG_ADDREG_TYPE_BINARY
:
291 case FLG_ADDREG_TYPE_DWORD
:
295 case FLG_ADDREG_TYPE_NONE
:
304 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
305 (Type
== REG_DWORD
&& SetupGetFieldCount (Context
) == 5))
309 if (Type
== REG_MULTI_SZ
)
311 if (!SetupGetMultiSzFieldW (Context
, 5, NULL
, 0, &Size
))
316 Str
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
, 0, Size
* sizeof(WCHAR
));
320 SetupGetMultiSzFieldW (Context
, 5, Str
, Size
, NULL
);
323 if (Flags
& FLG_ADDREG_APPEND
)
328 DPRINT1("append_multi_sz_value '%S' commented out, WHY??\n", ValueName
);
329 // append_multi_sz_value( hkey, value, str, size );
331 RtlFreeHeap (ProcessHeap
, 0, Str
);
334 /* else fall through to normal string handling */
338 if (!SetupGetStringFieldW(Context
, 5, NULL
, 0, &Size
))
343 Str
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
, 0, Size
* sizeof(WCHAR
));
347 SetupGetStringFieldW(Context
, 5, Str
, Size
, NULL
);
351 if (Type
== REG_DWORD
)
353 ULONG dw
= Str
? wcstoul (Str
, NULL
, 0) : 0;
355 DPRINT("setting dword %wZ to %lx\n", ValueName
, dw
);
357 NtSetValueKey (KeyHandle
,
366 DPRINT("setting value %wZ to %S\n", ValueName
, Str
);
370 NtSetValueKey (KeyHandle
,
375 Size
* sizeof(WCHAR
));
379 NtSetValueKey (KeyHandle
,
387 RtlFreeHeap (ProcessHeap
, 0, Str
);
389 else /* get the binary data */
393 if (!SetupGetBinaryField (Context
, 5, NULL
, 0, &Size
))
398 Data
= (unsigned char*) RtlAllocateHeap(ProcessHeap
, 0, Size
);
402 DPRINT("setting binary data %wZ len %lu\n", ValueName
, Size
);
403 SetupGetBinaryField (Context
, 5, Data
, Size
, NULL
);
406 NtSetValueKey (KeyHandle
,
413 RtlFreeHeap (ProcessHeap
, 0, Data
);
419 /***********************************************************************
422 * Called once for each AddReg and DelReg entry in a given section.
425 registry_callback(HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
428 OBJECT_ATTRIBUTES ObjectAttributes
;
429 UNICODE_STRING Name
, Value
;
430 PUNICODE_STRING ValuePtr
;
432 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
436 HANDLE RootKeyHandle
, KeyHandle
;
439 Ok
= SetupFindFirstLineW(hInf
, Section
, NULL
, &Context
);
441 return TRUE
; /* Don't fail if the section isn't present */
443 for (;Ok
; Ok
= SetupFindNextLine(&Context
, &Context
))
446 if (!SetupGetStringFieldW(&Context
, 1, Buffer
, sizeof(Buffer
)/sizeof(WCHAR
), NULL
))
448 RootKeyHandle
= GetRootKeyByName(Buffer
, &RootKeyName
);
453 if (!SetupGetStringFieldW(&Context
, 2, Buffer
, sizeof(Buffer
)/sizeof(WCHAR
), NULL
))
456 DPRINT("KeyName: <%S\\%S>\n", RootKeyName
, Buffer
);
459 if (!SetupGetIntField(&Context
, 4, (PINT
)&Flags
))
462 DPRINT("Flags: %lx\n", Flags
);
464 RtlInitUnicodeString(&Name
, Buffer
);
465 InitializeObjectAttributes(&ObjectAttributes
,
467 OBJ_CASE_INSENSITIVE
,
471 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
473 Status
= NtOpenKey(&KeyHandle
,
476 if (!NT_SUCCESS(Status
))
478 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
479 continue; /* ignore if it doesn't exist */
484 Status
= CreateNestedKey(&KeyHandle
,
487 REG_OPTION_NON_VOLATILE
);
488 if (!NT_SUCCESS(Status
))
490 DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
496 if (SetupGetStringFieldW(&Context
, 3, Buffer
, sizeof(Buffer
)/sizeof(WCHAR
), NULL
))
498 RtlInitUnicodeString(&Value
, Buffer
);
507 if (!do_reg_operation(KeyHandle
, ValuePtr
, &Context
, Flags
))
521 IN PCWSTR SourcePath
,
529 WCHAR FileNameBuffer
[MAX_PATH
];
531 /* Load the INF file from the installation media */
532 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2,
533 SourcePath
, FileName
);
535 hInf
= SetupOpenInfFileExW(FileNameBuffer
,
540 if (hInf
== INVALID_HANDLE_VALUE
)
542 DPRINT1("SetupOpenInfFileEx() failed\n");
547 if (!registry_callback(hInf
, L
"DelReg", FALSE
))
549 DPRINT1("registry_callback() failed\n");
550 SetupCloseInfFile(hInf
);
555 if (!registry_callback(hInf
, L
"AddReg", FALSE
))
557 DPRINT1("registry_callback() failed\n");
558 SetupCloseInfFile(hInf
);
562 if (!registry_callback(hInf
, L
"AddReg.NT" Architecture
, FALSE
))
564 DPRINT1("registry_callback() failed\n");
565 SetupCloseInfFile(hInf
);
569 SetupCloseInfFile(hInf
);
574 typedef enum _HIVE_UPDATE_STATE
576 Create
, // Create a new hive file and save possibly existing old one with a .old extension.
577 Repair
, // Re-create a new hive file and save possibly existing old one with a .brk extension.
578 Update
// Hive update, do not need to be recreated.
581 typedef struct _HIVE_LIST_ENTRY
583 PCWSTR HiveName
; // HiveFileName;
584 PCWSTR HiveRegistryPath
; // HiveRegMountPoint;
585 HANDLE PredefKeyHandle
;
587 HIVE_UPDATE_STATE State
;
588 // PUCHAR SecurityDescriptor;
589 // ULONG SecurityDescriptorLength;
590 } HIVE_LIST_ENTRY
, *PHIVE_LIST_ENTRY
;
592 #define NUMBER_OF_STANDARD_REGISTRY_HIVES 3
594 HIVE_LIST_ENTRY RegistryHives
[/*NUMBER_OF_STANDARD_REGISTRY_HIVES*/] =
596 { L
"SYSTEM" , L
"\\Registry\\Machine\\USetup_SYSTEM" , HKEY_LOCAL_MACHINE
, L
"SYSTEM" , Create
/* , SystemSecurity , sizeof(SystemSecurity) */ },
597 { L
"SOFTWARE", L
"\\Registry\\Machine\\USetup_SOFTWARE", HKEY_LOCAL_MACHINE
, L
"SOFTWARE", Create
/* , SoftwareSecurity, sizeof(SoftwareSecurity) */ },
598 { L
"DEFAULT" , L
"\\Registry\\User\\USetup_DEFAULT" , HKEY_USERS
, L
".DEFAULT", Create
/* , SystemSecurity , sizeof(SystemSecurity) */ },
600 // { L"BCD" , L"\\Registry\\Machine\\USetup_BCD", HKEY_LOCAL_MACHINE, L"BCD00000000", Create /* , BcdSecurity , sizeof(BcdSecurity) */ },
602 C_ASSERT(_countof(RegistryHives
) == NUMBER_OF_STANDARD_REGISTRY_HIVES
);
604 #define NUMBER_OF_SECURITY_REGISTRY_HIVES 2
606 /** These hives are created by LSASS during 2nd stage setup */
607 HIVE_LIST_ENTRY SecurityRegistryHives
[/*NUMBER_OF_SECURITY_REGISTRY_HIVES*/] =
609 { L
"SAM" , L
"\\Registry\\Machine\\USetup_SAM" , HKEY_LOCAL_MACHINE
, L
"SAM" , Create
/* , SystemSecurity , sizeof(SystemSecurity) */ },
610 { L
"SECURITY", L
"\\Registry\\Machine\\USetup_SECURITY", HKEY_LOCAL_MACHINE
, L
"SECURITY", Create
/* , NULL , 0 */ },
612 C_ASSERT(_countof(SecurityRegistryHives
) == NUMBER_OF_SECURITY_REGISTRY_HIVES
);
617 IN PUNICODE_STRING InstallPath
,
618 OUT PBOOLEAN ShouldRepairRegistry
)
621 BOOLEAN PrivilegeSet
[2] = {FALSE
, FALSE
};
624 /* Suppose first the registry hives do not have to be fully recreated */
625 *ShouldRepairRegistry
= FALSE
;
627 /* Acquire restore privilege */
628 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[0]);
629 if (!NT_SUCCESS(Status
))
631 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
632 /* Exit prematurely here.... */
636 /* Acquire backup privilege */
637 Status
= RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[1]);
638 if (!NT_SUCCESS(Status
))
640 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
641 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
642 /* Exit prematurely here.... */
646 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
648 Status
= VerifyRegistryHive(InstallPath
, RegistryHives
[i
].HiveName
);
649 if (!NT_SUCCESS(Status
))
651 DPRINT1("Registry hive '%S' needs repair!\n", RegistryHives
[i
].HiveName
);
652 RegistryHives
[i
].State
= Repair
;
653 *ShouldRepairRegistry
= TRUE
;
657 RegistryHives
[i
].State
= Update
;
661 /** These hives are created by LSASS during 2nd stage setup */
662 for (i
= 0; i
< ARRAYSIZE(SecurityRegistryHives
); ++i
)
664 Status
= VerifyRegistryHive(InstallPath
, SecurityRegistryHives
[i
].HiveName
);
665 if (!NT_SUCCESS(Status
))
667 DPRINT1("Registry hive '%S' needs repair!\n", SecurityRegistryHives
[i
].HiveName
);
668 SecurityRegistryHives
[i
].State
= Repair
;
670 * Note that it's not the role of the 1st-stage installer to fix
671 * the security hives. This should be done at 2nd-stage installation
677 SecurityRegistryHives
[i
].State
= Update
;
681 /* Reset the status (we succeeded in checking all the hives) */
682 Status
= STATUS_SUCCESS
;
684 /* Remove restore and backup privileges */
685 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, PrivilegeSet
[1], FALSE
, &PrivilegeSet
[1]);
686 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
692 RegInitializeRegistry(
693 IN PUNICODE_STRING InstallPath
)
697 UNICODE_STRING KeyName
;
698 OBJECT_ATTRIBUTES ObjectAttributes
;
699 BOOLEAN PrivilegeSet
[2] = {FALSE
, FALSE
};
703 /* Acquire restore privilege */
704 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[0]);
705 if (!NT_SUCCESS(Status
))
707 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
708 /* Exit prematurely here.... */
712 /* Acquire backup privilege */
713 Status
= RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[1]);
714 if (!NT_SUCCESS(Status
))
716 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
717 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
718 /* Exit prematurely here.... */
723 * Create the template proto-hive.
725 * Use a dummy root key name:
726 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
727 * - On Vista+, this is "CMI-CreateHive{guid}"
728 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
729 * for more information.
731 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
732 InitializeObjectAttributes(&ObjectAttributes
,
734 OBJ_CASE_INSENSITIVE
,
737 Status
= NtCreateKey(&KeyHandle
,
742 REG_OPTION_NON_VOLATILE
,
744 if (!NT_SUCCESS(Status
))
746 DPRINT1("NtCreateKey() failed to create the proto-hive (Status %lx)\n", Status
);
749 NtFlushKey(KeyHandle
);
751 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
753 if (RegistryHives
[i
].State
!= Create
&& RegistryHives
[i
].State
!= Repair
)
756 Status
= CreateRegistryFile(InstallPath
,
757 RegistryHives
[i
].HiveName
,
758 RegistryHives
[i
].State
!= Repair
, // RegistryHives[i].State == Create,
760 if (!NT_SUCCESS(Status
))
762 DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives
[i
].HiveName
, Status
);
763 /* Exit prematurely here.... */
764 /* That is now done, remove the proto-hive */
765 NtDeleteKey(KeyHandle
);
771 /* That is now done, remove the proto-hive */
772 NtDeleteKey(KeyHandle
);
777 * Prepare the registry root keys. Since we cannot create real registry keys
778 * inside the master keys (\Registry, \Registry\Machine or \Registry\User),
779 * we need to perform some SymLink tricks instead.
782 /* Our offline HKLM '\Registry\Machine' is inside '\Registry\Machine\SYSTEM\USetup_Machine' */
783 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].MountPoint
);
784 InitializeObjectAttributes(&ObjectAttributes
,
786 OBJ_CASE_INSENSITIVE
,
790 Status
= NtCreateKey(&KeyHandle
,
795 REG_OPTION_NON_VOLATILE
, // REG_OPTION_VOLATILE, // FIXME!
797 if (!NT_SUCCESS(Status
))
799 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName
, Status
);
802 RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
= KeyHandle
;
804 /* Our offline HKU '\Registry\User' is inside '\Registry\Machine\SYSTEM\USetup_User' */
805 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_USERS
)].MountPoint
);
806 InitializeObjectAttributes(&ObjectAttributes
,
808 OBJ_CASE_INSENSITIVE
,
812 Status
= NtCreateKey(&KeyHandle
,
817 REG_OPTION_NON_VOLATILE
, // REG_OPTION_VOLATILE, // FIXME!
819 if (!NT_SUCCESS(Status
))
821 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName
, Status
);
824 RootKeys
[GetPredefKeyIndex(HKEY_USERS
)].Handle
= KeyHandle
;
828 * Now properly mount the offline hive files
830 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
832 // if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
835 if (RegistryHives
[i
].State
== Create
|| RegistryHives
[i
].State
== Repair
)
837 Status
= ConnectRegistry(NULL
,
838 RegistryHives
[i
].HiveRegistryPath
,
840 RegistryHives
[i
].HiveName
841 /* SystemSecurity, sizeof(SystemSecurity) */);
842 if (!NT_SUCCESS(Status
))
844 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryHives
[i
].HiveName
, Status
);
847 /* Create the registry symlink to this key */
848 if (!CmpLinkKeyToHive(RootKeys
[GetPredefKeyIndex(RegistryHives
[i
].PredefKeyHandle
)].Handle
,
849 RegistryHives
[i
].RegSymLink
,
850 RegistryHives
[i
].HiveRegistryPath
))
852 DPRINT1("CmpLinkKeyToHive(%S) failed!\n", RegistryHives
[i
].HiveName
);
857 /* Create *DUMMY* volatile hives just to make the update procedure working */
859 RtlInitUnicodeString(&KeyName
, RegistryHives
[i
].RegSymLink
);
860 InitializeObjectAttributes(&ObjectAttributes
,
862 OBJ_CASE_INSENSITIVE
,
863 RootKeys
[GetPredefKeyIndex(RegistryHives
[i
].PredefKeyHandle
)].Handle
,
866 Status
= NtCreateKey(&KeyHandle
,
871 REG_OPTION_NON_VOLATILE
, // REG_OPTION_VOLATILE, // FIXME!
873 if (!NT_SUCCESS(Status
))
875 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName
, Status
);
883 /* HKCU is a handle to 'HKU\.DEFAULT' */
885 RtlInitUnicodeString(&KeyName
, L
".DEFAULT");
886 InitializeObjectAttributes(&ObjectAttributes
,
888 OBJ_CASE_INSENSITIVE
,
889 RootKeys
[GetPredefKeyIndex(HKEY_USERS
)].Handle
,
892 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_CURRENT_USER
)].MountPoint
);
893 InitializeObjectAttributes(&ObjectAttributes
,
895 OBJ_CASE_INSENSITIVE
,
900 Status
= NtOpenKey(&KeyHandle
,
903 if (!NT_SUCCESS(Status
))
905 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &KeyName
, Status
);
907 RootKeys
[GetPredefKeyIndex(HKEY_CURRENT_USER
)].Handle
= KeyHandle
;
910 /* HKCR is a handle to 'HKLM\Software\Classes' */
912 RtlInitUnicodeString(&KeyName
, L
"Software\\Classes");
913 InitializeObjectAttributes(&ObjectAttributes
,
915 OBJ_CASE_INSENSITIVE
,
916 RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
,
919 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_CLASSES_ROOT
)].MountPoint
);
920 InitializeObjectAttributes(&ObjectAttributes
,
922 OBJ_CASE_INSENSITIVE
,
927 /* We use NtCreateKey instead of NtOpenKey because Software\Classes doesn't exist originally */
928 Status
= NtCreateKey(&KeyHandle
,
933 REG_OPTION_NON_VOLATILE
,
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("NtCreateKey(%wZ) failed (Status %lx)\n", &KeyName
, Status
);
941 DPRINT1("NtCreateKey() succeeded to %s the %wZ key (Status %lx)\n",
942 Disposition
== REG_CREATED_NEW_KEY
? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
945 RootKeys
[GetPredefKeyIndex(HKEY_CLASSES_ROOT
)].Handle
= KeyHandle
;
948 Status
= STATUS_SUCCESS
;
951 /* Create the 'HKLM\SYSTEM\ControlSet001' key */
952 // REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"
953 RtlInitUnicodeString(&KeyName
, L
"SYSTEM\\ControlSet001");
954 InitializeObjectAttributes(&ObjectAttributes
,
956 OBJ_CASE_INSENSITIVE
,
957 RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
,
959 Status
= NtCreateKey(&KeyHandle
,
964 REG_OPTION_NON_VOLATILE
,
966 if (!NT_SUCCESS(Status
))
968 DPRINT1("NtCreateKey() failed to create the ControlSet001 key (Status %lx)\n", Status
);
973 DPRINT1("NtCreateKey() succeeded to %s the ControlSet001 key (Status %lx)\n",
974 Disposition
== REG_CREATED_NEW_KEY
? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
979 /* Create the 'HKLM\SYSTEM\CurrentControlSet' symlink */
980 if (!CmpLinkKeyToHive(RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
,
981 L
"SYSTEM\\CurrentControlSet",
982 REGISTRY_SETUP_MACHINE L
"SYSTEM\\ControlSet001"))
984 DPRINT1("CmpLinkKeyToHive(CurrentControlSet) failed!\n");
988 Status
= STATUS_SUCCESS
;
992 /* Remove restore and backup privileges */
993 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, PrivilegeSet
[1], FALSE
, &PrivilegeSet
[1]);
994 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
1001 IN PUNICODE_STRING InstallPath
)
1005 UNICODE_STRING KeyName
;
1006 OBJECT_ATTRIBUTES ObjectAttributes
;
1007 BOOLEAN PrivilegeSet
[2] = {FALSE
, FALSE
};
1009 WCHAR SrcPath
[MAX_PATH
];
1010 WCHAR DstPath
[MAX_PATH
];
1012 /* Acquire restore privilege */
1013 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[0]);
1014 if (!NT_SUCCESS(Status
))
1016 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
1017 /* Exit prematurely here.... */
1021 /* Acquire backup privilege */
1022 Status
= RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[1]);
1023 if (!NT_SUCCESS(Status
))
1025 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
1026 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
1027 /* Exit prematurely here.... */
1032 * Note that we don't need to explicitly remove the symlinks we have created
1033 * since they are created volatile, inside registry keys that will be however
1034 * removed explictly in the following.
1037 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
1039 if (RegistryHives
[i
].State
!= Create
&& RegistryHives
[i
].State
!= Repair
)
1041 RtlInitUnicodeString(&KeyName
, RegistryHives
[i
].RegSymLink
);
1042 InitializeObjectAttributes(&ObjectAttributes
,
1044 OBJ_CASE_INSENSITIVE
,
1045 RootKeys
[GetPredefKeyIndex(RegistryHives
[i
].PredefKeyHandle
)].Handle
,
1048 Status
= NtOpenKey(&KeyHandle
,
1051 if (!NT_SUCCESS(Status
))
1053 DPRINT1("NtOpenKey(%wZ) failed, Status 0x%08lx\n", &KeyName
, Status
);
1057 NtDeleteKey(KeyHandle
);
1062 Status
= DisconnectRegistry(NULL
,
1063 RegistryHives
[i
].HiveRegistryPath
,
1064 1 /* REG_FORCE_UNLOAD */);
1065 DPRINT1("Unmounting '%S' %s\n", RegistryHives
[i
].HiveRegistryPath
, NT_SUCCESS(Status
) ? "succeeded" : "failed");
1067 /* Switch the hive state to 'Update' */
1068 RegistryHives
[i
].State
= Update
;
1073 * FIXME: Once force-unloading keys is correctly fixed, I'll fix
1074 * this code that closes some of the registry keys that were opened
1075 * inside the hives we've just unmounted above...
1078 /* Remove the registry root keys */
1079 for (i
= 0; i
< ARRAYSIZE(RootKeys
); ++i
)
1081 if (RootKeys
[i
].Handle
)
1083 /**/NtFlushKey(RootKeys
[i
].Handle
);/**/ // FIXME: Why does it hang? Answer: because we have some problems in CMAPI!
1084 NtDeleteKey(RootKeys
[i
].Handle
);
1085 NtClose(RootKeys
[i
].Handle
);
1086 RootKeys
[i
].Handle
= NULL
;
1091 // RegBackupRegistry()
1093 /* Now backup the hives into .sav files */
1094 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
1096 if (RegistryHives
[i
].State
!= Create
&& RegistryHives
[i
].State
!= Repair
)
1099 CombinePaths(SrcPath
, ARRAYSIZE(SrcPath
), 3,
1100 InstallPath
->Buffer
, L
"System32\\config", RegistryHives
[i
].HiveName
);
1101 StringCchCopyW(DstPath
, ARRAYSIZE(DstPath
), SrcPath
);
1102 StringCchCatW(DstPath
, ARRAYSIZE(DstPath
), L
".sav");
1104 DPRINT1("Copy hive: %S ==> %S\n", SrcPath
, DstPath
);
1105 Status
= SetupCopyFile(SrcPath
, DstPath
, FALSE
);
1106 if (!NT_SUCCESS(Status
))
1108 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status
);
1113 /* Remove restore and backup privileges */
1114 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, PrivilegeSet
[1], FALSE
, &PrivilegeSet
[1]);
1115 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);