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 *****************************************************************/
19 /* FUNCTIONS ****************************************************************/
22 * This function is similar to the one in dlls/win32/advapi32/reg/reg.c
23 * TODO: I should review both of them very carefully, because they may need
24 * some adjustments in their NtCreateKey calls, especially for CreateOptions
28 CreateNestedKey(PHANDLE KeyHandle
,
29 ACCESS_MASK DesiredAccess
,
30 POBJECT_ATTRIBUTES ObjectAttributes
,
33 OBJECT_ATTRIBUTES LocalObjectAttributes
;
34 UNICODE_STRING LocalKeyName
;
37 USHORT FullNameLength
;
39 HANDLE LocalKeyHandle
;
41 Status
= NtCreateKey(KeyHandle
,
48 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
49 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
51 if (!NT_SUCCESS(Status
))
52 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", ObjectAttributes
->ObjectName
, Status
);
57 /* Copy object attributes */
58 RtlCopyMemory(&LocalObjectAttributes
,
60 sizeof(OBJECT_ATTRIBUTES
));
61 RtlCreateUnicodeString(&LocalKeyName
,
62 ObjectAttributes
->ObjectName
->Buffer
);
63 LocalObjectAttributes
.ObjectName
= &LocalKeyName
;
64 FullNameLength
= LocalKeyName
.Length
;
66 /* Remove the last part of the key name and try to create the key again. */
67 while (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
69 Ptr
= wcsrchr(LocalKeyName
.Buffer
, '\\');
70 if (Ptr
== NULL
|| Ptr
== LocalKeyName
.Buffer
)
72 Status
= STATUS_UNSUCCESSFUL
;
76 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
78 Status
= NtCreateKey(&LocalKeyHandle
,
80 &LocalObjectAttributes
,
83 REG_OPTION_NON_VOLATILE
,
85 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
86 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
87 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", LocalObjectAttributes
.ObjectName
, Status
);
90 if (!NT_SUCCESS(Status
))
92 RtlFreeUnicodeString(&LocalKeyName
);
96 /* Add removed parts of the key name and create them too. */
99 if (LocalKeyName
.Length
== FullNameLength
)
101 Status
= STATUS_SUCCESS
;
102 *KeyHandle
= LocalKeyHandle
;
105 NtClose(LocalKeyHandle
);
107 LocalKeyName
.Buffer
[LocalKeyName
.Length
/ sizeof(WCHAR
)] = L
'\\';
108 LocalKeyName
.Length
= wcslen(LocalKeyName
.Buffer
) * sizeof(WCHAR
);
110 Status
= NtCreateKey(&LocalKeyHandle
,
112 &LocalObjectAttributes
,
117 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName
, Status
);
118 if (!NT_SUCCESS(Status
))
120 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", LocalObjectAttributes
.ObjectName
, Status
);
125 RtlFreeUnicodeString(&LocalKeyName
);
132 * Should be called under SE_BACKUP_PRIVILEGE privilege
136 IN PUNICODE_STRING InstallPath
,
137 IN PCWSTR RegistryKey
,
138 IN BOOLEAN IsHiveNew
,
139 IN HANDLE ProtoKeyHandle
141 IN PUCHAR Descriptor,
142 IN ULONG DescriptorLength
146 /* '.old' is for old valid hives, while '.brk' is for old broken hives */
147 static PCWSTR Extensions
[] = {L
"old", L
"brk"};
151 UNICODE_STRING FileName
;
152 OBJECT_ATTRIBUTES ObjectAttributes
;
153 IO_STATUS_BLOCK IoStatusBlock
;
155 WCHAR PathBuffer
[MAX_PATH
];
156 WCHAR PathBuffer2
[MAX_PATH
];
158 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 3,
159 InstallPath
->Buffer
, L
"System32\\config", RegistryKey
);
161 Extension
= Extensions
[IsHiveNew
? 0 : 1];
164 // FIXME: The best, actually, would be to rename (move) the existing
165 // System32\config\RegistryKey file to System32\config\RegistryKey.old,
166 // and if it already existed some System32\config\RegistryKey.old, we should
167 // first rename this one into System32\config\RegistryKey_N.old before
168 // performing the original rename.
171 /* Check whether the registry hive file already existed, and if so, rename it */
172 if (DoesFileExist(NULL
, PathBuffer
))
176 DPRINT1("Registry hive '%S' already exists, rename it\n", PathBuffer
);
179 /* Try first by just appending the '.old' extension */
180 RtlStringCchPrintfW(PathBuffer2
, ARRAYSIZE(PathBuffer2
),
181 L
"%s.%s", PathBuffer
, Extension
);
183 while (DoesFileExist(NULL
, PathBuffer2
))
185 /* An old file already exists, increments its index, but not too much */
188 /* Append '_N.old' extension */
189 RtlStringCchPrintfW(PathBuffer2
, ARRAYSIZE(PathBuffer2
),
190 L
"%s_%lu.%s", PathBuffer
, i
, Extension
);
196 * Too many old files exist, we will rename the file
197 * using the name of the oldest one.
199 RtlStringCchPrintfW(PathBuffer2
, ARRAYSIZE(PathBuffer2
),
200 L
"%s.%s", PathBuffer
, Extension
);
206 /* Now rename the file (force the move) */
207 Status
= SetupMoveFile(PathBuffer
, PathBuffer2
, MOVEFILE_REPLACE_EXISTING
);
210 /* Create the file */
211 RtlInitUnicodeString(&FileName
, PathBuffer
);
212 InitializeObjectAttributes(&ObjectAttributes
,
214 OBJ_CASE_INSENSITIVE
,
215 NULL
, // Could have been InstallPath, etc...
218 Status
= NtCreateFile(&FileHandle
,
223 FILE_ATTRIBUTE_NORMAL
,
226 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
,
229 if (!NT_SUCCESS(Status
))
231 DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName
, Status
);
235 /* Save the selected hive into the file */
236 Status
= NtSaveKeyEx(ProtoKeyHandle
, FileHandle
, REG_LATEST_FORMAT
);
237 if (!NT_SUCCESS(Status
))
239 DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName
, Status
);
242 /* Close the file and return */
249 IN HANDLE RootLinkKeyHandle OPTIONAL
,
250 IN PCWSTR LinkKeyName
,
251 IN PCWSTR TargetKeyName
)
253 static UNICODE_STRING CmSymbolicLinkValueName
=
254 RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
257 OBJECT_ATTRIBUTES ObjectAttributes
;
258 UNICODE_STRING KeyName
;
259 HANDLE TargetKeyHandle
;
262 /* Initialize the object attributes */
263 RtlInitUnicodeString(&KeyName
, LinkKeyName
);
264 InitializeObjectAttributes(&ObjectAttributes
,
266 OBJ_CASE_INSENSITIVE
,
270 /* Create the link key */
271 Status
= NtCreateKey(&TargetKeyHandle
,
272 KEY_SET_VALUE
| KEY_CREATE_LINK
,
276 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
278 if (!NT_SUCCESS(Status
))
280 DPRINT1("CmpLinkKeyToHive: couldn't create %S, Status = 0x%08lx\n",
281 LinkKeyName
, Status
);
285 /* Check if the new key was actually created */
286 if (Disposition
!= REG_CREATED_NEW_KEY
)
288 DPRINT1("CmpLinkKeyToHive: %S already exists!\n", LinkKeyName
);
289 NtClose(TargetKeyHandle
);
293 /* Set the target key name as link target */
294 RtlInitUnicodeString(&KeyName
, TargetKeyName
);
295 Status
= NtSetValueKey(TargetKeyHandle
,
296 &CmSymbolicLinkValueName
,
302 /* Close the link key handle */
303 NtClose(TargetKeyHandle
);
305 if (!NT_SUCCESS(Status
))
307 DPRINT1("CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%08lx\n",
308 TargetKeyName
, Status
);
316 * Should be called under SE_RESTORE_PRIVILEGE privilege
320 IN HKEY RootKey OPTIONAL
,
321 IN PCWSTR RegMountPoint
,
322 // IN HANDLE RootDirectory OPTIONAL,
323 IN PUNICODE_STRING InstallPath
,
324 IN PCWSTR RegistryKey
326 IN PUCHAR Descriptor,
327 IN ULONG DescriptorLength
331 UNICODE_STRING KeyName
, FileName
;
332 OBJECT_ATTRIBUTES KeyObjectAttributes
;
333 OBJECT_ATTRIBUTES FileObjectAttributes
;
334 WCHAR PathBuffer
[MAX_PATH
];
336 RtlInitUnicodeString(&KeyName
, RegMountPoint
);
337 InitializeObjectAttributes(&KeyObjectAttributes
,
339 OBJ_CASE_INSENSITIVE
,
343 CombinePaths(PathBuffer
, ARRAYSIZE(PathBuffer
), 3,
344 InstallPath
->Buffer
, L
"System32\\config", RegistryKey
);
345 RtlInitUnicodeString(&FileName
, PathBuffer
);
346 InitializeObjectAttributes(&FileObjectAttributes
,
348 OBJ_CASE_INSENSITIVE
,
349 NULL
, // RootDirectory,
352 /* Mount the registry hive in the registry namespace */
353 return NtLoadKey(&KeyObjectAttributes
, &FileObjectAttributes
);
357 * Should be called under SE_RESTORE_PRIVILEGE privilege
361 IN HKEY RootKey OPTIONAL
,
362 IN PCWSTR RegMountPoint
,
365 UNICODE_STRING KeyName
;
366 OBJECT_ATTRIBUTES ObjectAttributes
;
368 RtlInitUnicodeString(&KeyName
, RegMountPoint
);
369 InitializeObjectAttributes(&ObjectAttributes
,
371 OBJ_CASE_INSENSITIVE
,
375 // NOTE: NtUnloadKey == NtUnloadKey2 with Flags == 0.
376 return NtUnloadKey2(&ObjectAttributes
, Flags
);
380 * Should be called under SE_RESTORE_PRIVILEGE privilege
384 // IN HKEY RootKey OPTIONAL,
385 // // IN HANDLE RootDirectory OPTIONAL,
386 IN PUNICODE_STRING InstallPath
,
387 IN PCWSTR RegistryKey
/* ,
388 IN PCWSTR RegMountPoint */)
392 /* Try to mount the specified registry hive */
393 Status
= ConnectRegistry(NULL
,
394 L
"\\Registry\\Machine\\USetup_VerifyHive",
398 if (!NT_SUCCESS(Status
))
400 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryKey
, Status
);
403 DPRINT1("VerifyRegistryHive: ConnectRegistry(%S) returns Status 0x%08lx\n", RegistryKey
, Status
);
406 // TODO: Check the Status error codes: STATUS_SUCCESS, STATUS_REGISTRY_RECOVERED,
407 // STATUS_REGISTRY_HIVE_RECOVERED, STATUS_REGISTRY_CORRUPT, STATUS_REGISTRY_IO_FAILED,
408 // STATUS_NOT_REGISTRY_FILE, STATUS_CANNOT_LOAD_REGISTRY_FILE ;
409 //(STATUS_HIVE_UNLOADED) ; STATUS_SYSTEM_HIVE_TOO_LARGE
412 if (Status
== STATUS_REGISTRY_HIVE_RECOVERED
) // NT_SUCCESS is still FALSE in this case!
413 DPRINT1("VerifyRegistryHive: Registry hive %S was recovered but some data may be lost (Status 0x%08lx)\n", RegistryKey
, Status
);
415 if (!NT_SUCCESS(Status
))
417 DPRINT1("VerifyRegistryHive: Registry hive %S is corrupted (Status 0x%08lx)\n", RegistryKey
, Status
);
421 if (Status
== STATUS_REGISTRY_RECOVERED
)
422 DPRINT1("VerifyRegistryHive: Registry hive %S succeeded recovered (Status 0x%08lx)\n", RegistryKey
, Status
);
424 /* Unmount the hive */
425 Status
= DisconnectRegistry(NULL
,
426 L
"\\Registry\\Machine\\USetup_VerifyHive",
428 if (!NT_SUCCESS(Status
))
430 DPRINT1("DisconnectRegistry(%S) failed, Status 0x%08lx\n", RegistryKey
, Status
);