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