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 *****************************************************************/
42 #if 1 // FIXME: Disable if setupapi.h is included in the code...
43 #define FLG_ADDREG_BINVALUETYPE 0x00000001
44 #define FLG_ADDREG_NOCLOBBER 0x00000002
45 #define FLG_ADDREG_DELVAL 0x00000004
46 #define FLG_ADDREG_APPEND 0x00000008
47 #define FLG_ADDREG_KEYONLY 0x00000010
48 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
49 #define FLG_ADDREG_TYPE_SZ 0x00000000
50 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
51 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
52 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
53 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
54 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
55 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
59 #define Architecture L"x86"
60 #elif defined(_M_AMD64)
61 #define Architecture L"amd64"
62 #elif defined(_M_IA64)
63 #define Architecture L"ia64"
65 #define Architecture L"arm"
67 #define Architecture L"ppc"
70 /* FUNCTIONS ****************************************************************/
72 #define REGISTRY_SETUP_MACHINE L"\\Registry\\Machine\\SYSTEM\\USetup_Machine\\"
73 #define REGISTRY_SETUP_USER L"\\Registry\\Machine\\SYSTEM\\USetup_User\\"
75 typedef struct _ROOT_KEY
80 } ROOT_KEY
, *PROOT_KEY
;
84 { L
"HKCR", REGISTRY_SETUP_MACHINE L
"SOFTWARE\\Classes\\", NULL
}, /* "\\Registry\\Machine\\SOFTWARE\\Classes\\" */ // HKEY_CLASSES_ROOT
85 { L
"HKCU", REGISTRY_SETUP_USER L
".DEFAULT\\" , NULL
}, /* "\\Registry\\User\\.DEFAULT\\" */ // HKEY_CURRENT_USER
86 { L
"HKLM", REGISTRY_SETUP_MACHINE
, NULL
}, /* "\\Registry\\Machine\\" */ // HKEY_LOCAL_MACHINE
87 { L
"HKU" , REGISTRY_SETUP_USER
, NULL
}, /* "\\Registry\\User\\" */ // HKEY_USERS
89 { L
"HKR", NULL
, NULL
},
93 #define IsPredefKey(HKey) \
94 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
96 #define GetPredefKeyIndex(HKey) \
97 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
100 GetRootKeyByPredefKey(
102 OUT PCWSTR
* RootKeyMountPoint OPTIONAL
)
104 ULONG_PTR Index
= GetPredefKeyIndex(KeyHandle
);
106 if (!IsPredefKey(KeyHandle
))
108 if (Index
>= ARRAYSIZE(RootKeys
))
111 if (RootKeyMountPoint
)
112 *RootKeyMountPoint
= RootKeys
[Index
].MountPoint
;
113 return RootKeys
[Index
].Handle
;
118 IN PCWSTR RootKeyName
,
119 OUT PCWSTR
* RootKeyMountPoint OPTIONAL
)
123 for (i
= 0; i
< ARRAYSIZE(RootKeys
); ++i
)
125 if (!_wcsicmp(RootKeyName
, RootKeys
[i
].Name
))
127 if (RootKeyMountPoint
)
128 *RootKeyMountPoint
= RootKeys
[i
].MountPoint
;
129 return RootKeys
[i
].Handle
;
137 /***********************************************************************
138 * append_multi_sz_value
140 * Append a multisz string to a multisz registry value.
142 // NOTE: Synced with setupapi/install.c ; see also mkhive/reginf.c
145 append_multi_sz_value (HANDLE hkey
,
147 const WCHAR
*strings
,
150 DWORD size
, type
, total
;
153 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
154 if (type
!= REG_MULTI_SZ
) return;
156 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
+ str_size
* sizeof(WCHAR
) ))) return;
157 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
159 /* compare each string against all the existing ones */
163 int len
= strlenW(strings
) + 1;
165 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
166 if (!strcmpiW( p
, strings
)) break;
168 if (!*p
) /* not found, need to append it */
170 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
178 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
179 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
182 HeapFree( GetProcessHeap(), 0, buffer
);
186 /***********************************************************************
187 * delete_multi_sz_value
189 * Remove a string from a multisz registry value.
192 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
195 WCHAR
*buffer
, *src
, *dst
;
197 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
198 if (type
!= REG_MULTI_SZ
) return;
199 /* allocate double the size, one for value before and one for after */
200 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
201 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
206 int len
= strlenW(src
) + 1;
207 if (strcmpiW( src
, string
))
209 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
215 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
217 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
218 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
219 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
222 HeapFree( GetProcessHeap(), 0, buffer
);
226 /***********************************************************************
229 * Perform an add/delete registry operation depending on the flags.
232 do_reg_operation(HANDLE KeyHandle
,
233 PUNICODE_STRING ValueName
,
241 if (Flags
& FLG_ADDREG_DELVAL
) /* deletion */
246 RegDeleteValueW( KeyHandle
, ValueName
);
250 RegDeleteKeyW( KeyHandle
, NULL
);
256 if (Flags
& FLG_ADDREG_KEYONLY
)
260 if (Flags
& (FLG_ADDREG_NOCLOBBER
| FLG_ADDREG_OVERWRITEONLY
))
262 BOOL exists
= !RegQueryValueExW( hkey
, ValueName
, NULL
, NULL
, NULL
, NULL
);
263 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
))
265 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
))
270 switch (Flags
& FLG_ADDREG_TYPE_MASK
)
272 case FLG_ADDREG_TYPE_SZ
:
276 case FLG_ADDREG_TYPE_MULTI_SZ
:
280 case FLG_ADDREG_TYPE_EXPAND_SZ
:
281 Type
= REG_EXPAND_SZ
;
284 case FLG_ADDREG_TYPE_BINARY
:
288 case FLG_ADDREG_TYPE_DWORD
:
292 case FLG_ADDREG_TYPE_NONE
:
301 if (!(Flags
& FLG_ADDREG_BINVALUETYPE
) ||
302 (Type
== REG_DWORD
&& SetupGetFieldCount (Context
) == 5))
306 if (Type
== REG_MULTI_SZ
)
308 if (!SetupGetMultiSzFieldW (Context
, 5, NULL
, 0, &Size
))
313 Str
= (WCHAR
*) RtlAllocateHeap(ProcessHeap
, 0, Size
* sizeof(WCHAR
));
317 SetupGetMultiSzFieldW (Context
, 5, Str
, Size
, NULL
);
320 if (Flags
& FLG_ADDREG_APPEND
)
325 DPRINT1("append_multi_sz_value '%S' commented out, WHY??\n", ValueName
);
326 // append_multi_sz_value( hkey, value, str, size );
328 RtlFreeHeap (ProcessHeap
, 0, Str
);
331 /* else fall through to normal string handling */
335 if (!SetupGetStringFieldW(Context
, 5, NULL
, 0, &Size
))
340 Str
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
, 0, Size
* sizeof(WCHAR
));
344 SetupGetStringFieldW(Context
, 5, Str
, Size
, NULL
);
348 if (Type
== REG_DWORD
)
350 ULONG dw
= Str
? wcstoul (Str
, NULL
, 0) : 0;
352 DPRINT("setting dword %wZ to %lx\n", ValueName
, dw
);
354 NtSetValueKey (KeyHandle
,
363 DPRINT("setting value %wZ to %S\n", ValueName
, Str
);
367 NtSetValueKey (KeyHandle
,
372 Size
* sizeof(WCHAR
));
376 NtSetValueKey (KeyHandle
,
384 RtlFreeHeap (ProcessHeap
, 0, Str
);
386 else /* get the binary data */
390 if (!SetupGetBinaryField (Context
, 5, NULL
, 0, &Size
))
395 Data
= (unsigned char*) RtlAllocateHeap(ProcessHeap
, 0, Size
);
399 DPRINT("setting binary data %wZ len %lu\n", ValueName
, Size
);
400 SetupGetBinaryField (Context
, 5, Data
, Size
, NULL
);
403 NtSetValueKey (KeyHandle
,
410 RtlFreeHeap (ProcessHeap
, 0, Data
);
416 /***********************************************************************
419 * Called once for each AddReg and DelReg entry in a given section.
422 registry_callback(HINF hInf
, PCWSTR Section
, BOOLEAN Delete
)
425 OBJECT_ATTRIBUTES ObjectAttributes
;
426 UNICODE_STRING Name
, Value
;
427 PUNICODE_STRING ValuePtr
;
429 WCHAR Buffer
[MAX_INF_STRING_LENGTH
];
433 HANDLE RootKeyHandle
, KeyHandle
;
436 Ok
= SetupFindFirstLineW(hInf
, Section
, NULL
, &Context
);
438 return TRUE
; /* Don't fail if the section isn't present */
440 for (;Ok
; Ok
= SetupFindNextLine(&Context
, &Context
))
443 if (!SetupGetStringFieldW(&Context
, 1, Buffer
, sizeof(Buffer
)/sizeof(WCHAR
), NULL
))
445 RootKeyHandle
= GetRootKeyByName(Buffer
, &RootKeyName
);
450 if (!SetupGetStringFieldW(&Context
, 2, Buffer
, sizeof(Buffer
)/sizeof(WCHAR
), NULL
))
453 DPRINT("KeyName: <%S\\%S>\n", RootKeyName
, Buffer
);
456 if (!SetupGetIntField(&Context
, 4, (PINT
)&Flags
))
459 DPRINT("Flags: %lx\n", Flags
);
461 RtlInitUnicodeString(&Name
, Buffer
);
462 InitializeObjectAttributes(&ObjectAttributes
,
464 OBJ_CASE_INSENSITIVE
,
468 if (Delete
|| (Flags
& FLG_ADDREG_OVERWRITEONLY
))
470 Status
= NtOpenKey(&KeyHandle
,
473 if (!NT_SUCCESS(Status
))
475 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
476 continue; /* ignore if it doesn't exist */
481 Status
= CreateNestedKey(&KeyHandle
,
484 REG_OPTION_NON_VOLATILE
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name
, Status
);
493 if (SetupGetStringFieldW(&Context
, 3, Buffer
, sizeof(Buffer
)/sizeof(WCHAR
), NULL
))
495 RtlInitUnicodeString(&Value
, Buffer
);
504 if (!do_reg_operation(KeyHandle
, ValuePtr
, &Context
, Flags
))
518 IN PCWSTR SourcePath
,
526 WCHAR FileNameBuffer
[MAX_PATH
];
528 /* Load the INF file from the installation media */
529 CombinePaths(FileNameBuffer
, ARRAYSIZE(FileNameBuffer
), 2,
530 SourcePath
, FileName
);
532 hInf
= SetupOpenInfFileExW(FileNameBuffer
,
537 if (hInf
== INVALID_HANDLE_VALUE
)
539 DPRINT1("SetupOpenInfFileEx() failed\n");
544 if (!registry_callback(hInf
, L
"DelReg", FALSE
))
546 DPRINT1("registry_callback() failed\n");
547 SetupCloseInfFile(hInf
);
552 if (!registry_callback(hInf
, L
"AddReg", FALSE
))
554 DPRINT1("registry_callback() failed\n");
555 SetupCloseInfFile(hInf
);
559 if (!registry_callback(hInf
, L
"AddReg.NT" Architecture
, FALSE
))
561 DPRINT1("registry_callback() failed\n");
562 SetupCloseInfFile(hInf
);
566 SetupCloseInfFile(hInf
);
571 typedef enum _HIVE_UPDATE_STATE
573 Create
, // Create a new hive file and save possibly existing old one with a .old extension.
574 Repair
, // Re-create a new hive file and save possibly existing old one with a .brk extension.
575 Update
// Hive update, do not need to be recreated.
578 typedef struct _HIVE_LIST_ENTRY
580 PCWSTR HiveName
; // HiveFileName;
581 PCWSTR HiveRegistryPath
; // HiveRegMountPoint;
582 HANDLE PredefKeyHandle
;
584 HIVE_UPDATE_STATE State
;
585 // PUCHAR SecurityDescriptor;
586 // ULONG SecurityDescriptorLength;
587 } HIVE_LIST_ENTRY
, *PHIVE_LIST_ENTRY
;
589 #define NUMBER_OF_STANDARD_REGISTRY_HIVES 3
591 HIVE_LIST_ENTRY RegistryHives
[/*NUMBER_OF_STANDARD_REGISTRY_HIVES*/] =
593 { L
"SYSTEM" , L
"\\Registry\\Machine\\USetup_SYSTEM" , HKEY_LOCAL_MACHINE
, L
"SYSTEM" , Create
/* , SystemSecurity , sizeof(SystemSecurity) */ },
594 { L
"SOFTWARE", L
"\\Registry\\Machine\\USetup_SOFTWARE", HKEY_LOCAL_MACHINE
, L
"SOFTWARE", Create
/* , SoftwareSecurity, sizeof(SoftwareSecurity) */ },
595 { L
"DEFAULT" , L
"\\Registry\\User\\USetup_DEFAULT" , HKEY_USERS
, L
".DEFAULT", Create
/* , SystemSecurity , sizeof(SystemSecurity) */ },
597 // { L"BCD" , L"\\Registry\\Machine\\USetup_BCD", HKEY_LOCAL_MACHINE, L"BCD00000000", Create /* , BcdSecurity , sizeof(BcdSecurity) */ },
599 C_ASSERT(_countof(RegistryHives
) == NUMBER_OF_STANDARD_REGISTRY_HIVES
);
601 #define NUMBER_OF_SECURITY_REGISTRY_HIVES 2
603 /** These hives are created by LSASS during 2nd stage setup */
604 HIVE_LIST_ENTRY SecurityRegistryHives
[/*NUMBER_OF_SECURITY_REGISTRY_HIVES*/] =
606 { L
"SAM" , L
"\\Registry\\Machine\\USetup_SAM" , HKEY_LOCAL_MACHINE
, L
"SAM" , Create
/* , SystemSecurity , sizeof(SystemSecurity) */ },
607 { L
"SECURITY", L
"\\Registry\\Machine\\USetup_SECURITY", HKEY_LOCAL_MACHINE
, L
"SECURITY", Create
/* , NULL , 0 */ },
609 C_ASSERT(_countof(SecurityRegistryHives
) == NUMBER_OF_SECURITY_REGISTRY_HIVES
);
614 IN PUNICODE_STRING InstallPath
,
615 OUT PBOOLEAN ShouldRepairRegistry
)
618 BOOLEAN PrivilegeSet
[2] = {FALSE
, FALSE
};
621 /* Suppose first the registry hives do not have to be fully recreated */
622 *ShouldRepairRegistry
= FALSE
;
624 /* Acquire restore privilege */
625 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[0]);
626 if (!NT_SUCCESS(Status
))
628 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
629 /* Exit prematurely here.... */
633 /* Acquire backup privilege */
634 Status
= RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[1]);
635 if (!NT_SUCCESS(Status
))
637 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
638 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
639 /* Exit prematurely here.... */
643 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
645 Status
= VerifyRegistryHive(InstallPath
, RegistryHives
[i
].HiveName
);
646 if (!NT_SUCCESS(Status
))
648 DPRINT1("Registry hive '%S' needs repair!\n", RegistryHives
[i
].HiveName
);
649 RegistryHives
[i
].State
= Repair
;
650 *ShouldRepairRegistry
= TRUE
;
654 RegistryHives
[i
].State
= Update
;
658 /** These hives are created by LSASS during 2nd stage setup */
659 for (i
= 0; i
< ARRAYSIZE(SecurityRegistryHives
); ++i
)
661 Status
= VerifyRegistryHive(InstallPath
, SecurityRegistryHives
[i
].HiveName
);
662 if (!NT_SUCCESS(Status
))
664 DPRINT1("Registry hive '%S' needs repair!\n", SecurityRegistryHives
[i
].HiveName
);
665 SecurityRegistryHives
[i
].State
= Repair
;
667 * Note that it's not the role of the 1st-stage installer to fix
668 * the security hives. This should be done at 2nd-stage installation
674 SecurityRegistryHives
[i
].State
= Update
;
678 /* Reset the status (we succeeded in checking all the hives) */
679 Status
= STATUS_SUCCESS
;
681 /* Remove restore and backup privileges */
682 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, PrivilegeSet
[1], FALSE
, &PrivilegeSet
[1]);
683 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
689 RegInitializeRegistry(
690 IN PUNICODE_STRING InstallPath
)
694 UNICODE_STRING KeyName
;
695 OBJECT_ATTRIBUTES ObjectAttributes
;
696 BOOLEAN PrivilegeSet
[2] = {FALSE
, FALSE
};
700 /* Acquire restore privilege */
701 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[0]);
702 if (!NT_SUCCESS(Status
))
704 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
705 /* Exit prematurely here.... */
709 /* Acquire backup privilege */
710 Status
= RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[1]);
711 if (!NT_SUCCESS(Status
))
713 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
714 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
715 /* Exit prematurely here.... */
720 * Create the template proto-hive.
722 * Use a dummy root key name:
723 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
724 * - On Vista+, this is "CMI-CreateHive{guid}"
725 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
726 * for more information.
728 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
729 InitializeObjectAttributes(&ObjectAttributes
,
731 OBJ_CASE_INSENSITIVE
,
734 Status
= NtCreateKey(&KeyHandle
,
739 REG_OPTION_NON_VOLATILE
,
741 if (!NT_SUCCESS(Status
))
743 DPRINT1("NtCreateKey() failed to create the proto-hive (Status %lx)\n", Status
);
746 NtFlushKey(KeyHandle
);
748 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
750 if (RegistryHives
[i
].State
!= Create
&& RegistryHives
[i
].State
!= Repair
)
753 Status
= CreateRegistryFile(InstallPath
,
754 RegistryHives
[i
].HiveName
,
755 RegistryHives
[i
].State
!= Repair
, // RegistryHives[i].State == Create,
757 if (!NT_SUCCESS(Status
))
759 DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives
[i
].HiveName
, Status
);
760 /* Exit prematurely here.... */
761 /* That is now done, remove the proto-hive */
762 NtDeleteKey(KeyHandle
);
768 /* That is now done, remove the proto-hive */
769 NtDeleteKey(KeyHandle
);
774 * Prepare the registry root keys. Since we cannot create real registry keys
775 * inside the master keys (\Registry, \Registry\Machine or \Registry\User),
776 * we need to perform some SymLink tricks instead.
779 /* Our offline HKLM '\Registry\Machine' is inside '\Registry\Machine\SYSTEM\USetup_Machine' */
780 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].MountPoint
);
781 InitializeObjectAttributes(&ObjectAttributes
,
783 OBJ_CASE_INSENSITIVE
,
787 Status
= NtCreateKey(&KeyHandle
,
792 REG_OPTION_NON_VOLATILE
, // REG_OPTION_VOLATILE, // FIXME!
794 if (!NT_SUCCESS(Status
))
796 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName
, Status
);
799 RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
= KeyHandle
;
801 /* Our offline HKU '\Registry\User' is inside '\Registry\Machine\SYSTEM\USetup_User' */
802 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_USERS
)].MountPoint
);
803 InitializeObjectAttributes(&ObjectAttributes
,
805 OBJ_CASE_INSENSITIVE
,
809 Status
= NtCreateKey(&KeyHandle
,
814 REG_OPTION_NON_VOLATILE
, // REG_OPTION_VOLATILE, // FIXME!
816 if (!NT_SUCCESS(Status
))
818 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName
, Status
);
821 RootKeys
[GetPredefKeyIndex(HKEY_USERS
)].Handle
= KeyHandle
;
825 * Now properly mount the offline hive files
827 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
829 // if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
832 if (RegistryHives
[i
].State
== Create
|| RegistryHives
[i
].State
== Repair
)
834 Status
= ConnectRegistry(NULL
,
835 RegistryHives
[i
].HiveRegistryPath
,
837 RegistryHives
[i
].HiveName
838 /* SystemSecurity, sizeof(SystemSecurity) */);
839 if (!NT_SUCCESS(Status
))
841 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryHives
[i
].HiveName
, Status
);
844 /* Create the registry symlink to this key */
845 if (!CmpLinkKeyToHive(RootKeys
[GetPredefKeyIndex(RegistryHives
[i
].PredefKeyHandle
)].Handle
,
846 RegistryHives
[i
].RegSymLink
,
847 RegistryHives
[i
].HiveRegistryPath
))
849 DPRINT1("CmpLinkKeyToHive(%S) failed!\n", RegistryHives
[i
].HiveName
);
854 /* Create *DUMMY* volatile hives just to make the update procedure working */
856 RtlInitUnicodeString(&KeyName
, RegistryHives
[i
].RegSymLink
);
857 InitializeObjectAttributes(&ObjectAttributes
,
859 OBJ_CASE_INSENSITIVE
,
860 RootKeys
[GetPredefKeyIndex(RegistryHives
[i
].PredefKeyHandle
)].Handle
,
863 Status
= NtCreateKey(&KeyHandle
,
868 REG_OPTION_NON_VOLATILE
, // REG_OPTION_VOLATILE, // FIXME!
870 if (!NT_SUCCESS(Status
))
872 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName
, Status
);
880 /* HKCU is a handle to 'HKU\.DEFAULT' */
882 RtlInitUnicodeString(&KeyName
, L
".DEFAULT");
883 InitializeObjectAttributes(&ObjectAttributes
,
885 OBJ_CASE_INSENSITIVE
,
886 RootKeys
[GetPredefKeyIndex(HKEY_USERS
)].Handle
,
889 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_CURRENT_USER
)].MountPoint
);
890 InitializeObjectAttributes(&ObjectAttributes
,
892 OBJ_CASE_INSENSITIVE
,
897 Status
= NtOpenKey(&KeyHandle
,
900 if (!NT_SUCCESS(Status
))
902 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &KeyName
, Status
);
904 RootKeys
[GetPredefKeyIndex(HKEY_CURRENT_USER
)].Handle
= KeyHandle
;
907 /* HKCR is a handle to 'HKLM\Software\Classes' */
909 RtlInitUnicodeString(&KeyName
, L
"Software\\Classes");
910 InitializeObjectAttributes(&ObjectAttributes
,
912 OBJ_CASE_INSENSITIVE
,
913 RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
,
916 RtlInitUnicodeString(&KeyName
, RootKeys
[GetPredefKeyIndex(HKEY_CLASSES_ROOT
)].MountPoint
);
917 InitializeObjectAttributes(&ObjectAttributes
,
919 OBJ_CASE_INSENSITIVE
,
924 /* We use NtCreateKey instead of NtOpenKey because Software\Classes doesn't exist originally */
925 Status
= NtCreateKey(&KeyHandle
,
930 REG_OPTION_NON_VOLATILE
,
932 if (!NT_SUCCESS(Status
))
934 DPRINT1("NtCreateKey(%wZ) failed (Status %lx)\n", &KeyName
, Status
);
938 DPRINT1("NtCreateKey() succeeded to %s the %wZ key (Status %lx)\n",
939 Disposition
== REG_CREATED_NEW_KEY
? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
942 RootKeys
[GetPredefKeyIndex(HKEY_CLASSES_ROOT
)].Handle
= KeyHandle
;
945 Status
= STATUS_SUCCESS
;
948 /* Create the 'HKLM\SYSTEM\ControlSet001' key */
949 // REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"
950 RtlInitUnicodeString(&KeyName
, L
"SYSTEM\\ControlSet001");
951 InitializeObjectAttributes(&ObjectAttributes
,
953 OBJ_CASE_INSENSITIVE
,
954 RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
,
956 Status
= NtCreateKey(&KeyHandle
,
961 REG_OPTION_NON_VOLATILE
,
963 if (!NT_SUCCESS(Status
))
965 DPRINT1("NtCreateKey() failed to create the ControlSet001 key (Status %lx)\n", Status
);
970 DPRINT1("NtCreateKey() succeeded to %s the ControlSet001 key (Status %lx)\n",
971 Disposition
== REG_CREATED_NEW_KEY
? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
976 /* Create the 'HKLM\SYSTEM\CurrentControlSet' symlink */
977 if (!CmpLinkKeyToHive(RootKeys
[GetPredefKeyIndex(HKEY_LOCAL_MACHINE
)].Handle
,
978 L
"SYSTEM\\CurrentControlSet",
979 REGISTRY_SETUP_MACHINE L
"SYSTEM\\ControlSet001"))
981 DPRINT1("CmpLinkKeyToHive(CurrentControlSet) failed!\n");
985 Status
= STATUS_SUCCESS
;
989 /* Remove restore and backup privileges */
990 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, PrivilegeSet
[1], FALSE
, &PrivilegeSet
[1]);
991 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
998 IN PUNICODE_STRING InstallPath
)
1002 UNICODE_STRING KeyName
;
1003 OBJECT_ATTRIBUTES ObjectAttributes
;
1004 BOOLEAN PrivilegeSet
[2] = {FALSE
, FALSE
};
1006 WCHAR SrcPath
[MAX_PATH
];
1007 WCHAR DstPath
[MAX_PATH
];
1009 /* Acquire restore privilege */
1010 Status
= RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[0]);
1011 if (!NT_SUCCESS(Status
))
1013 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
1014 /* Exit prematurely here.... */
1018 /* Acquire backup privilege */
1019 Status
= RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, TRUE
, FALSE
, &PrivilegeSet
[1]);
1020 if (!NT_SUCCESS(Status
))
1022 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status
);
1023 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);
1024 /* Exit prematurely here.... */
1029 * Note that we don't need to explicitly remove the symlinks we have created
1030 * since they are created volatile, inside registry keys that will be however
1031 * removed explictly in the following.
1034 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
1036 if (RegistryHives
[i
].State
!= Create
&& RegistryHives
[i
].State
!= Repair
)
1038 RtlInitUnicodeString(&KeyName
, RegistryHives
[i
].RegSymLink
);
1039 InitializeObjectAttributes(&ObjectAttributes
,
1041 OBJ_CASE_INSENSITIVE
,
1042 RootKeys
[GetPredefKeyIndex(RegistryHives
[i
].PredefKeyHandle
)].Handle
,
1045 Status
= NtOpenKey(&KeyHandle
,
1048 if (!NT_SUCCESS(Status
))
1050 DPRINT1("NtOpenKey(%wZ) failed, Status 0x%08lx\n", &KeyName
, Status
);
1054 NtDeleteKey(KeyHandle
);
1059 Status
= DisconnectRegistry(NULL
,
1060 RegistryHives
[i
].HiveRegistryPath
,
1061 1 /* REG_FORCE_UNLOAD */);
1062 DPRINT1("Unmounting '%S' %s\n", RegistryHives
[i
].HiveRegistryPath
, NT_SUCCESS(Status
) ? "succeeded" : "failed");
1064 /* Switch the hive state to 'Update' */
1065 RegistryHives
[i
].State
= Update
;
1070 * FIXME: Once force-unloading keys is correctly fixed, I'll fix
1071 * this code that closes some of the registry keys that were opened
1072 * inside the hives we've just unmounted above...
1075 /* Remove the registry root keys */
1076 for (i
= 0; i
< ARRAYSIZE(RootKeys
); ++i
)
1078 if (RootKeys
[i
].Handle
)
1080 /**/NtFlushKey(RootKeys
[i
].Handle
);/**/ // FIXME: Why does it hang? Answer: because we have some problems in CMAPI!
1081 NtDeleteKey(RootKeys
[i
].Handle
);
1082 NtClose(RootKeys
[i
].Handle
);
1083 RootKeys
[i
].Handle
= NULL
;
1088 // RegBackupRegistry()
1090 /* Now backup the hives into .sav files */
1091 for (i
= 0; i
< ARRAYSIZE(RegistryHives
); ++i
)
1093 if (RegistryHives
[i
].State
!= Create
&& RegistryHives
[i
].State
!= Repair
)
1096 CombinePaths(SrcPath
, ARRAYSIZE(SrcPath
), 3,
1097 InstallPath
->Buffer
, L
"System32\\config", RegistryHives
[i
].HiveName
);
1098 RtlStringCchCopyW(DstPath
, ARRAYSIZE(DstPath
), SrcPath
);
1099 RtlStringCchCatW(DstPath
, ARRAYSIZE(DstPath
), L
".sav");
1101 DPRINT1("Copy hive: %S ==> %S\n", SrcPath
, DstPath
);
1102 Status
= SetupCopyFile(SrcPath
, DstPath
, FALSE
);
1103 if (!NT_SUCCESS(Status
))
1105 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status
);
1110 /* Remove restore and backup privileges */
1111 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE
, PrivilegeSet
[1], FALSE
, &PrivilegeSet
[1]);
1112 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE
, PrivilegeSet
[0], FALSE
, &PrivilegeSet
[0]);