1 /* 2 * PROJECT: ReactOS API Tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Test for NtLoadKey and NtUnloadKey 5 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) 6 */ 7 8 #include "precomp.h" 9 10 /* See xdk/cmtypes.h */ 11 #define REG_CREATED_NEW_KEY 1 12 #define REG_OPENED_EXISTING_KEY 2 13 14 #define REG_FORCE_UNLOAD 1 15 16 #if 1 17 18 #define NDEBUG 19 #include <debug.h> 20 21 #else 22 23 #define DPRINT(fmt, ...) printf("(%s:%d) " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 24 #define DPRINT1(fmt, ...) printf("(%s:%d) " fmt, __FILE__, __LINE__, ##__VA_ARGS__); 25 26 #endif 27 28 static NTSTATUS (NTAPI *pNtUnloadKey2)(POBJECT_ATTRIBUTES, ULONG); 29 30 static BOOLEAN 31 RetrieveCurrentModuleNTDirectory( 32 OUT PUNICODE_STRING NtPath) 33 { 34 WCHAR ModulePath[MAX_PATH]; 35 PWSTR PathSep; 36 37 /* Retrieve the current path where the test is running */ 38 GetModuleFileNameW(NULL, ModulePath, _countof(ModulePath)); 39 PathSep = wcsrchr(ModulePath, L'\\'); 40 if (!PathSep) 41 PathSep = ModulePath + wcslen(ModulePath); 42 *PathSep = UNICODE_NULL; 43 44 /* Convert the path to NT format and work with it for now on */ 45 return RtlDosPathNameToNtPathName_U(ModulePath, NtPath, NULL, NULL); 46 } 47 48 static NTSTATUS 49 CreateRegKey( 50 OUT PHANDLE KeyHandle, 51 IN HANDLE RootKey OPTIONAL, 52 IN PUNICODE_STRING KeyName, 53 IN ULONG CreateOptions, 54 OUT PULONG Disposition OPTIONAL) 55 { 56 OBJECT_ATTRIBUTES ObjectAttributes; 57 58 InitializeObjectAttributes(&ObjectAttributes, 59 KeyName, 60 OBJ_CASE_INSENSITIVE, 61 RootKey, 62 NULL); 63 return NtCreateKey(KeyHandle, 64 KEY_ALL_ACCESS, 65 &ObjectAttributes, 66 0, 67 NULL, 68 CreateOptions, 69 Disposition); 70 } 71 72 static NTSTATUS 73 CreateProtoHive( 74 OUT PHANDLE KeyHandle) 75 { 76 NTSTATUS Status; 77 UNICODE_STRING KeyName; 78 79 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV"); 80 Status = CreateRegKey(KeyHandle, 81 NULL, 82 &KeyName, 83 REG_OPTION_NON_VOLATILE, 84 NULL); 85 if (!NT_SUCCESS(Status)) 86 return Status; 87 88 NtFlushKey(KeyHandle); 89 return Status; 90 } 91 92 static VOID 93 DestroyProtoHive( 94 IN HANDLE KeyHandle) 95 { 96 NtDeleteKey(KeyHandle); 97 NtClose(KeyHandle); 98 } 99 100 static NTSTATUS 101 OpenDirectoryByHandleOrPath( 102 OUT PHANDLE RootPathHandle, 103 IN HANDLE RootDirectory OPTIONAL, 104 IN PUNICODE_STRING RootPath OPTIONAL) 105 { 106 NTSTATUS Status; 107 OBJECT_ATTRIBUTES ObjectAttributes; 108 IO_STATUS_BLOCK IoStatusBlock; 109 110 *RootPathHandle = NULL; 111 112 /* 113 * RootDirectory and RootPath cannot be either both NULL 114 * or both non-NULL, when being specified. 115 */ 116 if ((!RootDirectory && !RootPath) || 117 ( RootDirectory && RootPath)) 118 { 119 return STATUS_INVALID_PARAMETER; 120 } 121 122 if (!RootDirectory && RootPath) 123 { 124 /* Open the root directory path */ 125 InitializeObjectAttributes(&ObjectAttributes, 126 RootPath, 127 OBJ_CASE_INSENSITIVE, 128 NULL, 129 NULL); 130 Status = NtOpenFile(RootPathHandle, 131 // FILE_TRAVERSE is needed to be able to use the handle as RootDirectory for future InitializeObjectAttributes calls. 132 FILE_LIST_DIRECTORY | FILE_ADD_FILE /* | FILE_ADD_SUBDIRECTORY */ | FILE_TRAVERSE | SYNCHRONIZE, 133 &ObjectAttributes, 134 &IoStatusBlock, 135 FILE_SHARE_READ | FILE_SHARE_WRITE, 136 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE /* | FILE_OPEN_FOR_BACKUP_INTENT */); 137 if (!NT_SUCCESS(Status)) 138 { 139 DPRINT1("NtOpenFile(%wZ) failed, Status 0x%08lx\n", RootPath, Status); 140 return Status; 141 } 142 143 /* Mark the handle as being opened locally */ 144 *RootPathHandle = (HANDLE)((ULONG_PTR)*RootPathHandle | 1); 145 } 146 else if (RootDirectory && !RootPath) 147 { 148 *RootPathHandle = RootDirectory; 149 } 150 // No other cases possible 151 152 return STATUS_SUCCESS; 153 } 154 155 /* 156 * Should be called under privileges 157 */ 158 static NTSTATUS 159 CreateRegistryFile( 160 IN HANDLE RootDirectory OPTIONAL, 161 IN PUNICODE_STRING RootPath OPTIONAL, 162 IN PCWSTR RegistryKey, 163 IN HANDLE ProtoKeyHandle) 164 { 165 NTSTATUS Status; 166 HANDLE RootPathHandle, FileHandle; 167 UNICODE_STRING FileName; 168 OBJECT_ATTRIBUTES ObjectAttributes; 169 IO_STATUS_BLOCK IoStatusBlock; 170 171 /* Open the root directory */ 172 Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath); 173 if (!NT_SUCCESS(Status)) 174 { 175 DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n", Status); 176 return Status; 177 } 178 179 /* Create the file */ 180 RtlInitUnicodeString(&FileName, RegistryKey); 181 InitializeObjectAttributes(&ObjectAttributes, 182 &FileName, 183 OBJ_CASE_INSENSITIVE, 184 (HANDLE)((ULONG_PTR)RootPathHandle & ~1), // Remove the opened-locally flag 185 NULL); 186 Status = NtCreateFile(&FileHandle, 187 FILE_GENERIC_WRITE /* | DELETE */, 188 &ObjectAttributes, 189 &IoStatusBlock, 190 NULL, 191 FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */, 192 0, 193 FILE_OVERWRITE_IF, 194 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, 195 NULL, 196 0); 197 if (!NT_SUCCESS(Status)) 198 { 199 DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName, Status); 200 goto Cleanup; 201 } 202 203 /* Save the selected hive into the file */ 204 Status = NtSaveKeyEx(ProtoKeyHandle, FileHandle, REG_LATEST_FORMAT); 205 if (!NT_SUCCESS(Status)) 206 { 207 DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName, Status); 208 } 209 210 /* Close the file, the root directory (if opened locally), and return */ 211 NtClose(FileHandle); 212 Cleanup: 213 if ((ULONG_PTR)RootPathHandle & 1) NtClose((HANDLE)((ULONG_PTR)RootPathHandle & ~1)); 214 return Status; 215 } 216 217 /* 218 * Should be called under privileges 219 */ 220 static NTSTATUS 221 MyDeleteFile( 222 IN HANDLE RootDirectory OPTIONAL, 223 IN PUNICODE_STRING RootPath OPTIONAL, 224 IN PCWSTR FileName, 225 IN BOOLEAN ForceDelete) // ForceDelete can be used to delete read-only files 226 { 227 NTSTATUS Status; 228 HANDLE RootPathHandle; 229 UNICODE_STRING NtPath; 230 OBJECT_ATTRIBUTES ObjectAttributes; 231 IO_STATUS_BLOCK IoStatusBlock; 232 HANDLE FileHandle; 233 FILE_DISPOSITION_INFORMATION FileDispInfo; 234 BOOLEAN RetryOnce = FALSE; 235 236 /* Open the root directory */ 237 Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath); 238 if (!NT_SUCCESS(Status)) 239 { 240 DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n", Status); 241 return Status; 242 } 243 244 /* Open the directory name that was passed in */ 245 RtlInitUnicodeString(&NtPath, FileName); 246 InitializeObjectAttributes(&ObjectAttributes, 247 &NtPath, 248 OBJ_CASE_INSENSITIVE, 249 RootPathHandle, 250 NULL); 251 252 Retry: /* We go back there once if RetryOnce == TRUE */ 253 Status = NtOpenFile(&FileHandle, 254 DELETE | FILE_READ_ATTRIBUTES | 255 (RetryOnce ? FILE_WRITE_ATTRIBUTES : 0), 256 &ObjectAttributes, 257 &IoStatusBlock, 258 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 259 FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT); 260 if (!NT_SUCCESS(Status)) 261 { 262 DPRINT1("NtOpenFile failed with Status 0x%08lx\n", Status); 263 return Status; 264 } 265 266 if (RetryOnce) 267 { 268 FILE_BASIC_INFORMATION FileInformation; 269 270 Status = NtQueryInformationFile(FileHandle, 271 &IoStatusBlock, 272 &FileInformation, 273 sizeof(FILE_BASIC_INFORMATION), 274 FileBasicInformation); 275 if (!NT_SUCCESS(Status)) 276 { 277 DPRINT1("NtQueryInformationFile failed with Status 0x%08lx\n", Status); 278 NtClose(FileHandle); 279 return Status; 280 } 281 282 FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL; 283 Status = NtSetInformationFile(FileHandle, 284 &IoStatusBlock, 285 &FileInformation, 286 sizeof(FILE_BASIC_INFORMATION), 287 FileBasicInformation); 288 NtClose(FileHandle); 289 if (!NT_SUCCESS(Status)) 290 { 291 DPRINT1("NtSetInformationFile failed with Status 0x%08lx\n", Status); 292 return Status; 293 } 294 } 295 296 /* Ask for the file to be deleted */ 297 FileDispInfo.DeleteFile = TRUE; 298 Status = NtSetInformationFile(FileHandle, 299 &IoStatusBlock, 300 &FileDispInfo, 301 sizeof(FILE_DISPOSITION_INFORMATION), 302 FileDispositionInformation); 303 NtClose(FileHandle); 304 305 if (!NT_SUCCESS(Status)) 306 DPRINT1("Deletion of file '%S' failed, Status 0x%08lx\n", FileName, Status); 307 308 // FIXME: Check the precise value of Status! 309 if (!NT_SUCCESS(Status) && ForceDelete && !RetryOnce) 310 { 311 /* Retry once */ 312 RetryOnce = TRUE; 313 goto Retry; 314 } 315 316 /* Return result to the caller */ 317 return Status; 318 } 319 320 /* 321 * Should be called under privileges 322 */ 323 static NTSTATUS 324 ConnectRegistry( 325 IN HANDLE RootKey OPTIONAL, 326 IN PCWSTR RegMountPoint, 327 IN HANDLE RootDirectory OPTIONAL, 328 IN PUNICODE_STRING RootPath OPTIONAL, 329 IN PCWSTR RegistryKey) 330 { 331 NTSTATUS Status; 332 HANDLE RootPathHandle; 333 UNICODE_STRING KeyName, FileName; 334 OBJECT_ATTRIBUTES KeyObjectAttributes; 335 OBJECT_ATTRIBUTES FileObjectAttributes; 336 337 /* Open the root directory */ 338 Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath); 339 if (!NT_SUCCESS(Status)) 340 { 341 DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n", Status); 342 return Status; 343 } 344 345 RtlInitUnicodeString(&KeyName, RegMountPoint); 346 InitializeObjectAttributes(&KeyObjectAttributes, 347 &KeyName, 348 OBJ_CASE_INSENSITIVE, 349 RootKey, 350 NULL); 351 352 RtlInitUnicodeString(&FileName, RegistryKey); 353 InitializeObjectAttributes(&FileObjectAttributes, 354 &FileName, 355 OBJ_CASE_INSENSITIVE, 356 (HANDLE)((ULONG_PTR)RootPathHandle & ~1), // Remove the opened-locally flag 357 NULL); 358 359 /* Mount the registry hive in the registry namespace */ 360 Status = NtLoadKey(&KeyObjectAttributes, &FileObjectAttributes); 361 362 /* Close the root directory (if opened locally), and return */ 363 if ((ULONG_PTR)RootPathHandle & 1) NtClose((HANDLE)((ULONG_PTR)RootPathHandle & ~1)); 364 return Status; 365 } 366 367 /* 368 * Should be called under privileges 369 */ 370 static NTSTATUS 371 DisconnectRegistry( 372 IN HANDLE RootKey OPTIONAL, 373 IN PCWSTR RegMountPoint, 374 IN ULONG Flags) 375 { 376 UNICODE_STRING KeyName; 377 OBJECT_ATTRIBUTES ObjectAttributes; 378 379 RtlInitUnicodeString(&KeyName, RegMountPoint); 380 InitializeObjectAttributes(&ObjectAttributes, 381 &KeyName, 382 OBJ_CASE_INSENSITIVE, 383 RootKey, 384 NULL); 385 if (!pNtUnloadKey2) 386 { 387 win_skip("NtUnloadKey2 unavailable, using NtUnloadKey. Flags %lu\n", Flags); 388 return NtUnloadKey(&ObjectAttributes); 389 } 390 return pNtUnloadKey2(&ObjectAttributes, Flags); 391 } 392 393 394 START_TEST(NtLoadUnloadKey) 395 { 396 typedef struct _HIVE_LIST_ENTRY 397 { 398 PCWSTR HiveName; 399 PCWSTR RegMountPoint; 400 } HIVE_LIST_ENTRY; 401 402 static const HIVE_LIST_ENTRY RegistryHives[] = 403 { 404 { L"TestHive1", L"\\Registry\\Machine\\TestHive1" }, 405 { L"TestHive2", L"\\Registry\\Machine\\TestHive2" }, 406 }; 407 408 NTSTATUS Status; 409 UNICODE_STRING NtTestPath; 410 UNICODE_STRING KeyName; 411 HANDLE KeyHandle; 412 ULONG Disposition; 413 UINT i; 414 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE}; 415 WCHAR PathBuffer[MAX_PATH]; 416 417 pNtUnloadKey2 = (PVOID)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtUnloadKey2"); 418 419 /* Retrieve our current directory */ 420 RetrieveCurrentModuleNTDirectory(&NtTestPath); 421 422 /* Acquire restore privilege */ 423 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]); 424 if (!NT_SUCCESS(Status)) 425 { 426 skip("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status); 427 /* Exit prematurely here.... */ 428 // goto Cleanup; 429 RtlFreeUnicodeString(&NtTestPath); 430 return; 431 } 432 433 /* Acquire backup privilege */ 434 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]); 435 if (!NT_SUCCESS(Status)) 436 { 437 skip("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status); 438 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]); 439 /* Exit prematurely here.... */ 440 // goto Cleanup; 441 RtlFreeUnicodeString(&NtTestPath); 442 return; 443 } 444 445 /* Create the template proto-hive */ 446 Status = CreateProtoHive(&KeyHandle); 447 if (!NT_SUCCESS(Status)) 448 { 449 skip("CreateProtoHive() failed to create the proto-hive; Status 0x%08lx\n", Status); 450 goto Cleanup; 451 } 452 453 /* Create two registry hive files from it */ 454 for (i = 0; i < _countof(RegistryHives); ++i) 455 { 456 Status = CreateRegistryFile(NULL, &NtTestPath, 457 RegistryHives[i].HiveName, 458 KeyHandle); 459 if (!NT_SUCCESS(Status)) 460 { 461 DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status); 462 /* Exit prematurely here.... */ 463 break; 464 } 465 } 466 467 /* That is now done, remove the proto-hive */ 468 DestroyProtoHive(KeyHandle); 469 470 /* Exit prematurely here if we failed */ 471 if (!NT_SUCCESS(Status)) 472 goto Cleanup; 473 474 475 /***********************************************************************************************/ 476 477 478 /* Now, mount the first hive */ 479 Status = ConnectRegistry(NULL, RegistryHives[0].RegMountPoint, 480 NULL, &NtTestPath, 481 RegistryHives[0].HiveName); 482 if (!NT_SUCCESS(Status)) 483 { 484 DPRINT1("ConnectRegistry('%wZ\\%S', '%S') failed, Status 0x%08lx\n", 485 &NtTestPath, RegistryHives[0].HiveName, RegistryHives[0].RegMountPoint, Status); 486 } 487 488 /* Create or open a key inside the mounted hive */ 489 StringCchPrintfW(PathBuffer, _countof(PathBuffer), L"%s\\%s", RegistryHives[0].RegMountPoint, L"MyKey_1"); 490 RtlInitUnicodeString(&KeyName, PathBuffer); 491 492 KeyHandle = NULL; 493 Status = CreateRegKey(&KeyHandle, 494 NULL, 495 &KeyName, 496 REG_OPTION_NON_VOLATILE, 497 &Disposition); 498 if (!NT_SUCCESS(Status)) 499 { 500 DPRINT1("CreateRegKey(%wZ) failed (Status %lx)\n", &KeyName, Status); 501 } 502 else 503 { 504 DPRINT1("CreateRegKey(%wZ) succeeded to %s the key (Status %lx)\n", 505 &KeyName, 506 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open", 507 Status); 508 } 509 510 /* The key handle must be valid here */ 511 Status = NtFlushKey(KeyHandle); 512 ok_ntstatus(Status, STATUS_SUCCESS); 513 514 /* Attempt to unmount the hive, with the handle key still opened */ 515 Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 0); // Same as NtUnloadKey(&ObjectAttributes); 516 DPRINT1("Unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed"); 517 ok_ntstatus(Status, STATUS_CANNOT_DELETE); 518 519 /* The key handle should still be valid here */ 520 Status = NtFlushKey(KeyHandle); 521 ok_ntstatus(Status, STATUS_SUCCESS); 522 523 /* Force-unmount the hive, with the handle key still opened */ 524 Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, REG_FORCE_UNLOAD); 525 DPRINT1("Force-unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed"); 526 ok_hex(Status, STATUS_SUCCESS); 527 528 /* The key handle should not be valid anymore */ 529 Status = NtFlushKey(KeyHandle); 530 if (Status != STATUS_KEY_DELETED /* Win2k3 */ && 531 Status != STATUS_HIVE_UNLOADED /* Win7+ */) 532 { 533 ok_ntstatus(Status, STATUS_KEY_DELETED); 534 } 535 536 /* The key handle should not be valid anymore */ 537 Status = NtDeleteKey(KeyHandle); 538 ok_ntstatus(Status, STATUS_SUCCESS); 539 540 /* Close by principle the handle, but should this fail? */ 541 Status = NtClose(KeyHandle); 542 ok_ntstatus(Status, STATUS_SUCCESS); 543 544 545 /***********************************************************************************************/ 546 547 548 /* Now, mount the first hive, again */ 549 Status = ConnectRegistry(NULL, RegistryHives[0].RegMountPoint, 550 NULL, &NtTestPath, 551 RegistryHives[0].HiveName); 552 if (!NT_SUCCESS(Status)) 553 { 554 DPRINT1("ConnectRegistry('%wZ\\%S', '%S') failed, Status 0x%08lx\n", 555 &NtTestPath, RegistryHives[0].HiveName, RegistryHives[0].RegMountPoint, Status); 556 } 557 558 /* Create or open a key inside the mounted hive */ 559 StringCchPrintfW(PathBuffer, _countof(PathBuffer), L"%s\\%s", RegistryHives[0].RegMountPoint, L"MyKey_2"); 560 RtlInitUnicodeString(&KeyName, PathBuffer); 561 562 KeyHandle = NULL; 563 Status = CreateRegKey(&KeyHandle, 564 NULL, 565 &KeyName, 566 REG_OPTION_NON_VOLATILE, 567 &Disposition); 568 if (!NT_SUCCESS(Status)) 569 { 570 DPRINT1("CreateRegKey(%wZ) failed (Status %lx)\n", &KeyName, Status); 571 } 572 else 573 { 574 DPRINT1("CreateRegKey(%wZ) succeeded to %s the key (Status %lx)\n", 575 &KeyName, 576 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open", 577 Status); 578 } 579 580 /* The key handle must be valid here */ 581 Status = NtFlushKey(KeyHandle); 582 ok_ntstatus(Status, STATUS_SUCCESS); 583 584 /* Delete the key, this should succeed */ 585 Status = NtDeleteKey(KeyHandle); 586 ok_ntstatus(Status, STATUS_SUCCESS); 587 588 /* Close the handle, this should succeed */ 589 Status = NtClose(KeyHandle); 590 ok_ntstatus(Status, STATUS_SUCCESS); 591 592 /* Attempt to unmount the hive (no forcing), this should succeed */ 593 Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 0); // Same as NtUnloadKey(&ObjectAttributes); 594 DPRINT1("Unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed"); 595 ok_ntstatus(Status, STATUS_SUCCESS); 596 597 /* Force-unmount the hive (it is already unmounted), this should fail */ 598 Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, REG_FORCE_UNLOAD); 599 DPRINT1("Force-unmounting '%S' %s\n", RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" : "failed"); 600 ok_hex(Status, STATUS_INVALID_PARAMETER); 601 602 #if 0 603 /* Close by principle the handle, but should this fail? */ 604 Status = NtClose(KeyHandle); 605 ok_ntstatus(Status, STATUS_SUCCESS); 606 #endif 607 608 609 /***********************************************************************************************/ 610 611 612 Cleanup: 613 614 /* Destroy the hive files */ 615 for (i = 0; i < _countof(RegistryHives); ++i) 616 { 617 Status = MyDeleteFile(NULL, &NtTestPath, 618 RegistryHives[i].HiveName, TRUE); 619 if (!NT_SUCCESS(Status)) 620 DPRINT1("MyDeleteFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status); 621 } 622 623 /* Remove restore and backup privileges */ 624 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]); 625 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]); 626 627 RtlFreeUnicodeString(&NtTestPath); 628 } 629