[RAPPS] Stopped GCC whining (fixed GCC build)
[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 #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 }