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
RetrieveCurrentModuleNTDirectory(OUT PUNICODE_STRING NtPath)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
CreateRegKey(OUT PHANDLE KeyHandle,IN HANDLE RootKey OPTIONAL,IN PUNICODE_STRING KeyName,IN ULONG CreateOptions,OUT PULONG Disposition OPTIONAL)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
CreateProtoHive(OUT PHANDLE KeyHandle)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
DestroyProtoHive(IN HANDLE KeyHandle)93 DestroyProtoHive(
94 IN HANDLE KeyHandle)
95 {
96 NtDeleteKey(KeyHandle);
97 NtClose(KeyHandle);
98 }
99
100 static NTSTATUS
OpenDirectoryByHandleOrPath(OUT PHANDLE RootPathHandle,IN HANDLE RootDirectory OPTIONAL,IN PUNICODE_STRING RootPath OPTIONAL)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
CreateRegistryFile(IN HANDLE RootDirectory OPTIONAL,IN PUNICODE_STRING RootPath OPTIONAL,IN PCWSTR RegistryKey,IN HANDLE ProtoKeyHandle)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
MyDeleteFile(IN HANDLE RootDirectory OPTIONAL,IN PUNICODE_STRING RootPath OPTIONAL,IN PCWSTR FileName,IN BOOLEAN ForceDelete)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
ConnectRegistry(IN HANDLE RootKey OPTIONAL,IN PCWSTR RegMountPoint,IN HANDLE RootDirectory OPTIONAL,IN PUNICODE_STRING RootPath OPTIONAL,IN PCWSTR RegistryKey)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
DisconnectRegistry(IN HANDLE RootKey OPTIONAL,IN PCWSTR RegMountPoint,IN ULONG Flags)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
START_TEST(NtLoadUnloadKey)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