2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Setup Library
4 * FILE: base/setup/lib/regutil.c
5 * PURPOSE: Registry utility functions
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 /* INCLUDES *****************************************************************/
23 // HACK!! These functions should actually be moved in the setup lib!
24 // For the moment, see usetup/filesup.c (or .h)
29 IN PCWSTR SourceFileName
,
30 IN PCWSTR DestinationFileName
,
31 IN BOOLEAN FailIfExists
);
33 #define MOVEFILE_REPLACE_EXISTING 1
37 IN PCWSTR ExistingFileName
,
38 IN PCWSTR NewFileName
,
43 /* FUNCTIONS ****************************************************************/
46 * This function is similar to the one in dlls/win32/advapi32/reg/reg.c
47 * TODO: I should review both of them very carefully, because they may need
48 * some adjustments in their NtCreateKey calls, especially for CreateOptions
52 CreateNestedKey(PHANDLE KeyHandle
,
53 ACCESS_MASK DesiredAccess
,
54 POBJECT_ATTRIBUTES ObjectAttributes
,
57 OBJECT_ATTRIBUTES LocalObjectAttributes
;
58 UNICODE_STRING LocalKeyName
;
61 USHORT FullNameLength
;
63 HANDLE LocalKeyHandle
;
65 Status
= NtCreateKey(KeyHandle
,
72 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
73 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
75 if (!NT_SUCCESS(Status
))
76 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
81 /* Copy object attributes */
82 RtlCopyMemory(&LocalObjectAttributes
,
84 sizeof(OBJECT_ATTRIBUTES
));
85 RtlCreateUnicodeString(&LocalKeyName
,
86 ObjectAttributes
->ObjectName
->Buffer
);
87 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
88 FullNameLength
= LocalKeyName
.Length
;
90 /* Remove the last part of the key name and try to create the key again. */
91 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
93 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
94 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
96 Status
= STATUS_UNSUCCESSFUL
;
100 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
102 Status
= NtCreateKey(&LocalKeyHandle
,
104 &LocalObjectAttributes
,
107 REG_OPTION_NON_VOLATILE
,
109 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
110 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
111 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", LocalObjectAttributes
.ObjectName
, Status
);
114 if (!NT_SUCCESS(Status
))
116 RtlFreeUnicodeString(&LocalKeyName
);
120 /* Add removed parts of the key name and create them too. */
123 if (LocalKeyName
.Length
== FullNameLength
)
125 Status
= STATUS_SUCCESS
;
126 *KeyHandle
= LocalKeyHandle
;
129 NtClose(LocalKeyHandle
);
131 LocalKeyName
.Buffer
[LocalKeyName
.Length
/ sizeof(WCHAR
)] = L
'\\';
132 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
134 Status
= NtCreateKey(&LocalKeyHandle
,
136 &LocalObjectAttributes
,
141 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
142 if (!NT_SUCCESS(Status
))
144 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", LocalObjectAttributes
.ObjectName
, Status
);
149 RtlFreeUnicodeString(&LocalKeyName
);
156 * Should be called under SE_BACKUP_PRIVILEGE privilege
160 IN PUNICODE_STRING InstallPath
,
161 IN PCWSTR RegistryKey
,
162 IN BOOLEAN IsHiveNew
,
163 IN HANDLE ProtoKeyHandle
165 IN PUCHAR Descriptor,
166 IN ULONG DescriptorLength
170 /* '.old' is for old valid hives, while '.brk' is for old broken hives */
171 static PCWSTR Extensions
[] = {L
"old", L
"brk"};
175 UNICODE_STRING FileName
;
176 OBJECT_ATTRIBUTES ObjectAttributes
;
177 IO_STATUS_BLOCK IoStatusBlock
;
179 WCHAR PathBuffer
[MAX_PATH
];
180 WCHAR PathBuffer2
[MAX_PATH
];
182 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 3,
183 InstallPath
->Buffer
, L
"System32\\config", RegistryKey
);
185 Extension
= Extensions
[IsHiveNew
? 0 : 1];
188 // FIXME: The best, actually, would be to rename (move) the existing
189 // System32\config\RegistryKey file to System32\config\RegistryKey.old,
190 // and if it already existed some System32\config\RegistryKey.old, we should
191 // first rename this one into System32\config\RegistryKey_N.old before
192 // performing the original rename.
195 /* Check whether the registry hive file already existed, and if so, rename it */
196 if (DoesFileExist(NULL
, PathBuffer
))
200 DPRINT1("Registry hive '%S' already exists, rename it\n", PathBuffer
);
203 /* Try first by just appending the '.old' extension */
204 StringCchPrintfW(PathBuffer2
, ARRAYSIZE(PathBuffer2
), L
"%s.%s", PathBuffer
, Extension
);
206 while (DoesFileExist(NULL
, PathBuffer2
))
208 /* An old file already exists, increments its index, but not too much */
211 /* Append '_N.old' extension */
212 StringCchPrintfW(PathBuffer2
, ARRAYSIZE(PathBuffer2
), L
"%s_%lu.%s", PathBuffer
, i
, Extension
);
218 * Too many old files exist, we will rename the file
219 * using the name of the oldest one.
221 StringCchPrintfW(PathBuffer2
, ARRAYSIZE(PathBuffer2
), L
"%s.%s", PathBuffer
, Extension
);
227 /* Now rename the file (force the move) */
228 Status
= SetupMoveFile(PathBuffer
, PathBuffer2
, MOVEFILE_REPLACE_EXISTING
);
231 /* Create the file */
232 RtlInitUnicodeString(&FileName
, PathBuffer
);
233 InitializeObjectAttributes(&ObjectAttributes
,
235 OBJ_CASE_INSENSITIVE
,
236 NULL
, // Could have been InstallPath, etc...
239 Status
= NtCreateFile(&FileHandle
,
244 FILE_ATTRIBUTE_NORMAL
,
247 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
,
250 if (!NT_SUCCESS(Status
))
252 DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName
, Status
);
256 /* Save the selected hive into the file */
257 Status
= NtSaveKeyEx(ProtoKeyHandle
, FileHandle
, REG_LATEST_FORMAT
);
258 if (!NT_SUCCESS(Status
))
260 DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName
, Status
);
263 /* Close the file and return */
270 IN HANDLE RootLinkKeyHandle OPTIONAL
,
271 IN PCWSTR LinkKeyName
,
272 IN PCWSTR TargetKeyName
)
274 static UNICODE_STRING CmSymbolicLinkValueName
=
275 RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
278 OBJECT_ATTRIBUTES ObjectAttributes
;
279 UNICODE_STRING KeyName
;
280 HANDLE TargetKeyHandle
;
283 /* Initialize the object attributes */
284 RtlInitUnicodeString(&KeyName
, LinkKeyName
);
285 InitializeObjectAttributes(&ObjectAttributes
,
287 OBJ_CASE_INSENSITIVE
,
291 /* Create the link key */
292 Status
= NtCreateKey(&TargetKeyHandle
,
293 KEY_SET_VALUE
| KEY_CREATE_LINK
,
297 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
299 if (!NT_SUCCESS(Status
))
301 DPRINT1("CmpLinkKeyToHive: couldn't create %S, Status = 0x%08lx\n",
302 LinkKeyName
, Status
);
306 /* Check if the new key was actually created */
307 if (Disposition
!= REG_CREATED_NEW_KEY
)
309 DPRINT1("CmpLinkKeyToHive: %S already exists!\n", LinkKeyName
);
310 NtClose(TargetKeyHandle
);
314 /* Set the target key name as link target */
315 RtlInitUnicodeString(&KeyName
, TargetKeyName
);
316 Status
= NtSetValueKey(TargetKeyHandle
,
317 &CmSymbolicLinkValueName
,
323 /* Close the link key handle */
324 NtClose(TargetKeyHandle
);
326 if (!NT_SUCCESS(Status
))
328 DPRINT1("CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%08lx\n",
329 TargetKeyName
, Status
);
337 * Should be called under SE_RESTORE_PRIVILEGE privilege
341 IN HKEY RootKey OPTIONAL
,
342 IN PCWSTR RegMountPoint
,
343 // IN HANDLE RootDirectory OPTIONAL,
344 IN PUNICODE_STRING InstallPath
,
345 IN PCWSTR RegistryKey
347 IN PUCHAR Descriptor,
348 IN ULONG DescriptorLength
352 UNICODE_STRING KeyName
, FileName
;
353 OBJECT_ATTRIBUTES KeyObjectAttributes
;
354 OBJECT_ATTRIBUTES FileObjectAttributes
;
355 WCHAR PathBuffer
[MAX_PATH
];
357 RtlInitUnicodeString(&KeyName
, RegMountPoint
);
358 InitializeObjectAttributes(&KeyObjectAttributes
,
360 OBJ_CASE_INSENSITIVE
,
364 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 3,
365 InstallPath
->Buffer
, L
"System32\\config", RegistryKey
);
366 RtlInitUnicodeString(&FileName
, PathBuffer
);
367 InitializeObjectAttributes(&FileObjectAttributes
,
369 OBJ_CASE_INSENSITIVE
,
370 NULL
, // RootDirectory,
373 /* Mount the registry hive in the registry namespace */
374 return NtLoadKey(&KeyObjectAttributes
, &FileObjectAttributes
);
378 * Should be called under SE_RESTORE_PRIVILEGE privilege
382 IN HKEY RootKey OPTIONAL
,
383 IN PCWSTR RegMountPoint
,
386 UNICODE_STRING KeyName
;
387 OBJECT_ATTRIBUTES ObjectAttributes
;
389 RtlInitUnicodeString(&KeyName
, RegMountPoint
);
390 InitializeObjectAttributes(&ObjectAttributes
,
392 OBJ_CASE_INSENSITIVE
,
396 // NOTE: NtUnloadKey == NtUnloadKey2 with Flags == 0.
397 return NtUnloadKey2(&ObjectAttributes
, Flags
);
401 * Should be called under SE_RESTORE_PRIVILEGE privilege
405 // IN HKEY RootKey OPTIONAL,
406 // // IN HANDLE RootDirectory OPTIONAL,
407 IN PUNICODE_STRING InstallPath
,
408 IN PCWSTR RegistryKey
/* ,
409 IN PCWSTR RegMountPoint */)
413 /* Try to mount the specified registry hive */
414 Status
= ConnectRegistry(NULL
,
415 L
"\\Registry\\Machine\\USetup_VerifyHive",
419 if (!NT_SUCCESS(Status
))
421 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryKey
, Status
);
424 DPRINT1("VerifyRegistryHive: ConnectRegistry(%S) returns Status 0x%08lx\n", RegistryKey
, Status
);
427 // TODO: Check the Status error codes: STATUS_SUCCESS, STATUS_REGISTRY_RECOVERED,
428 // STATUS_REGISTRY_HIVE_RECOVERED, STATUS_REGISTRY_CORRUPT, STATUS_REGISTRY_IO_FAILED,
429 // STATUS_NOT_REGISTRY_FILE, STATUS_CANNOT_LOAD_REGISTRY_FILE ;
430 //(STATUS_HIVE_UNLOADED) ; STATUS_SYSTEM_HIVE_TOO_LARGE
433 if (Status
== STATUS_REGISTRY_HIVE_RECOVERED
) // NT_SUCCESS is still FALSE in this case!
434 DPRINT1("VerifyRegistryHive: Registry hive %S was recovered but some data may be lost (Status 0x%08lx)\n", RegistryKey
, Status
);
436 if (!NT_SUCCESS(Status
))
438 DPRINT1("VerifyRegistryHive: Registry hive %S is corrupted (Status 0x%08lx)\n", RegistryKey
, Status
);
442 if (Status
== STATUS_REGISTRY_RECOVERED
)
443 DPRINT1("VerifyRegistryHive: Registry hive %S succeeded recovered (Status 0x%08lx)\n", RegistryKey
, Status
);
445 /* Unmount the hive */
446 Status
= DisconnectRegistry(NULL
,
447 L
"\\Registry\\Machine\\USetup_VerifyHive",
449 if (!NT_SUCCESS(Status
))
451 DPRINT1("DisconnectRegistry(%S) failed, Status 0x%08lx\n", RegistryKey
, Status
);