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