Author: hbelusca
Date: Sat Jun 17 20:08:48 2017
New Revision: 75078
URL:
http://svn.reactos.org/svn/reactos?rev=75078&view=rev
Log:
[NTDLL_APITEST]: Add tests for NtLoadKey and NtUnloadKey.
CORE-13448
Added:
trunk/rostests/apitests/ntdll/NtLoadUnloadKey.c (with props)
Modified:
trunk/rostests/apitests/ntdll/CMakeLists.txt
trunk/rostests/apitests/ntdll/testlist.c
Modified: trunk/rostests/apitests/ntdll/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/CMakeLists…
==============================================================================
--- trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] Sat Jun 17 20:08:48 2017
@@ -10,6 +10,7 @@
NtCreateThread.c
NtDeleteKey.c
NtFreeVirtualMemory.c
+ NtLoadUnloadKey.c
NtMapViewOfSection.c
NtMutant.c
NtOpenProcessToken.c
Added: trunk/rostests/apitests/ntdll/NtLoadUnloadKey.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/NtLoadUnlo…
==============================================================================
--- trunk/rostests/apitests/ntdll/NtLoadUnloadKey.c (added)
+++ trunk/rostests/apitests/ntdll/NtLoadUnloadKey.c [iso-8859-1] Sat Jun 17 20:08:48 2017
@@ -0,0 +1,633 @@
+/*
+ * PROJECT: ReactOS API Tests
+ * LICENSE: GPLv2+ - See COPYING in the top level directory
+ * PURPOSE: Test for NtLoadKey and NtUnloadKey
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+#include <stdio.h>
+
+#include <apitest.h>
+#include <strsafe.h>
+
+#define WIN32_NO_STATUS
+#include <ndk/rtlfuncs.h>
+#include <ndk/cmfuncs.h>
+#include <ndk/cmtypes.h>
+#include <ndk/iofuncs.h>
+#include <ndk/obfuncs.h>
+#include <ndk/setypes.h>
+
+/* See xdk/cmtypes.h */
+#define REG_CREATED_NEW_KEY 1
+#define REG_OPENED_EXISTING_KEY 2
+
+/* Vista+ */
+#define STATUS_HIVE_UNLOADED ((NTSTATUS)0xC0000425)
+
+#if 1
+
+ #define NDEBUG
+ #include <debug.h>
+
+#else
+
+ #define DPRINT(fmt, ...) printf("(%s:%d) " fmt, __FILE__, __LINE__,
##__VA_ARGS__);
+ #define DPRINT1(fmt, ...) printf("(%s:%d) " fmt, __FILE__, __LINE__,
##__VA_ARGS__);
+
+#endif
+
+
+static BOOLEAN
+RetrieveCurrentModuleNTDirectory(
+ OUT PUNICODE_STRING NtPath)
+{
+ WCHAR ModulePath[MAX_PATH];
+ PWSTR PathSep;
+
+ /* Retrieve the current path where the test is running */
+ GetModuleFileNameW(NULL, ModulePath, _countof(ModulePath));
+ PathSep = wcsrchr(ModulePath, L'\\');
+ if (!PathSep)
+ PathSep = ModulePath + wcslen(ModulePath);
+ *PathSep = UNICODE_NULL;
+
+ /* Convert the path to NT format and work with it for now on */
+ return RtlDosPathNameToNtPathName_U(ModulePath, NtPath, NULL, NULL);
+}
+
+static NTSTATUS
+CreateRegKey(
+ OUT PHANDLE KeyHandle,
+ IN HANDLE RootKey OPTIONAL,
+ IN PUNICODE_STRING KeyName,
+ IN ULONG CreateOptions,
+ OUT PULONG Disposition OPTIONAL)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ KeyName,
+ OBJ_CASE_INSENSITIVE,
+ RootKey,
+ NULL);
+ return NtCreateKey(KeyHandle,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ CreateOptions,
+ Disposition);
+}
+
+static NTSTATUS
+CreateProtoHive(
+ OUT PHANDLE KeyHandle)
+{
+ NTSTATUS Status;
+ UNICODE_STRING KeyName;
+
+ RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
+ Status = CreateRegKey(KeyHandle,
+ NULL,
+ &KeyName,
+ REG_OPTION_NON_VOLATILE,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ NtFlushKey(KeyHandle);
+ return Status;
+}
+
+static VOID
+DestroyProtoHive(
+ IN HANDLE KeyHandle)
+{
+ NtDeleteKey(KeyHandle);
+ NtClose(KeyHandle);
+}
+
+static NTSTATUS
+OpenDirectoryByHandleOrPath(
+ OUT PHANDLE RootPathHandle,
+ IN HANDLE RootDirectory OPTIONAL,
+ IN PUNICODE_STRING RootPath OPTIONAL)
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ *RootPathHandle = NULL;
+
+ /*
+ * RootDirectory and RootPath cannot be either both NULL
+ * or both non-NULL, when being specified.
+ */
+ if ((!RootDirectory && !RootPath) ||
+ ( RootDirectory && RootPath))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!RootDirectory && RootPath)
+ {
+ /* Open the root directory path */
+ InitializeObjectAttributes(&ObjectAttributes,
+ RootPath,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenFile(RootPathHandle,
+ // FILE_TRAVERSE is needed to be able to use the handle as
RootDirectory for future InitializeObjectAttributes calls.
+ FILE_LIST_DIRECTORY | FILE_ADD_FILE /* |
FILE_ADD_SUBDIRECTORY */ | FILE_TRAVERSE | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE /* |
FILE_OPEN_FOR_BACKUP_INTENT */);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtOpenFile(%wZ) failed, Status 0x%08lx\n", RootPath,
Status);
+ return Status;
+ }
+
+ /* Mark the handle as being opened locally */
+ *RootPathHandle = (HANDLE)((ULONG_PTR)*RootPathHandle | 1);
+ }
+ else if (RootDirectory && !RootPath)
+ {
+ *RootPathHandle = RootDirectory;
+ }
+ // No other cases possible
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * Should be called under privileges
+ */
+static NTSTATUS
+CreateRegistryFile(
+ IN HANDLE RootDirectory OPTIONAL,
+ IN PUNICODE_STRING RootPath OPTIONAL,
+ IN PCWSTR RegistryKey,
+ IN HANDLE ProtoKeyHandle)
+{
+ NTSTATUS Status;
+ HANDLE RootPathHandle, FileHandle;
+ UNICODE_STRING FileName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ /* Open the root directory */
+ Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n",
Status);
+ return Status;
+ }
+
+ /* Create the file */
+ RtlInitUnicodeString(&FileName, RegistryKey);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &FileName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)((ULONG_PTR)RootPathHandle & ~1), // Remove
the opened-locally flag
+ NULL);
+ Status = NtCreateFile(&FileHandle,
+ FILE_GENERIC_WRITE /* | DELETE */,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */,
+ 0,
+ FILE_OVERWRITE_IF,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
+ NULL,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName,
Status);
+ goto Cleanup;
+ }
+
+ /* Save the selected hive into the file */
+ Status = NtSaveKeyEx(ProtoKeyHandle, FileHandle, REG_LATEST_FORMAT);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName,
Status);
+ }
+
+ /* Close the file, the root directory (if opened locally), and return */
+ NtClose(FileHandle);
+Cleanup:
+ if ((ULONG_PTR)RootPathHandle & 1) NtClose((HANDLE)((ULONG_PTR)RootPathHandle
& ~1));
+ return Status;
+}
+
+/*
+ * Should be called under privileges
+ */
+static NTSTATUS
+MyDeleteFile(
+ IN HANDLE RootDirectory OPTIONAL,
+ IN PUNICODE_STRING RootPath OPTIONAL,
+ IN PCWSTR FileName,
+ IN BOOLEAN ForceDelete) // ForceDelete can be used to delete read-only files
+{
+ NTSTATUS Status;
+ HANDLE RootPathHandle;
+ UNICODE_STRING NtPath;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ HANDLE FileHandle;
+ FILE_DISPOSITION_INFORMATION FileDispInfo;
+ BOOLEAN RetryOnce = FALSE;
+
+ /* Open the root directory */
+ Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n",
Status);
+ return Status;
+ }
+
+ /* Open the directory name that was passed in */
+ RtlInitUnicodeString(&NtPath, FileName);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &NtPath,
+ OBJ_CASE_INSENSITIVE,
+ RootPathHandle,
+ NULL);
+
+Retry: /* We go back there once if RetryOnce == TRUE */
+ Status = NtOpenFile(&FileHandle,
+ DELETE | FILE_READ_ATTRIBUTES |
+ (RetryOnce ? FILE_WRITE_ATTRIBUTES : 0),
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtOpenFile failed with Status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ if (RetryOnce)
+ {
+ FILE_BASIC_INFORMATION FileInformation;
+
+ Status = NtQueryInformationFile(FileHandle,
+ &IoStatusBlock,
+ &FileInformation,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtQueryInformationFile failed with Status 0x%08lx\n",
Status);
+ NtClose(FileHandle);
+ return Status;
+ }
+
+ FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ Status = NtSetInformationFile(FileHandle,
+ &IoStatusBlock,
+ &FileInformation,
+ sizeof(FILE_BASIC_INFORMATION),
+ FileBasicInformation);
+ NtClose(FileHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtSetInformationFile failed with Status 0x%08lx\n",
Status);
+ return Status;
+ }
+ }
+
+ /* Ask for the file to be deleted */
+ FileDispInfo.DeleteFile = TRUE;
+ Status = NtSetInformationFile(FileHandle,
+ &IoStatusBlock,
+ &FileDispInfo,
+ sizeof(FILE_DISPOSITION_INFORMATION),
+ FileDispositionInformation);
+ NtClose(FileHandle);
+
+ if (!NT_SUCCESS(Status))
+ DPRINT1("Deletion of file '%S' failed, Status 0x%08lx\n",
FileName, Status);
+
+ // FIXME: Check the precise value of Status!
+ if (!NT_SUCCESS(Status) && ForceDelete && !RetryOnce)
+ {
+ /* Retry once */
+ RetryOnce = TRUE;
+ goto Retry;
+ }
+
+ /* Return result to the caller */
+ return Status;
+}
+
+/*
+ * Should be called under privileges
+ */
+static NTSTATUS
+ConnectRegistry(
+ IN HANDLE RootKey OPTIONAL,
+ IN PCWSTR RegMountPoint,
+ IN HANDLE RootDirectory OPTIONAL,
+ IN PUNICODE_STRING RootPath OPTIONAL,
+ IN PCWSTR RegistryKey)
+{
+ NTSTATUS Status;
+ HANDLE RootPathHandle;
+ UNICODE_STRING KeyName, FileName;
+ OBJECT_ATTRIBUTES KeyObjectAttributes;
+ OBJECT_ATTRIBUTES FileObjectAttributes;
+
+ /* Open the root directory */
+ Status = OpenDirectoryByHandleOrPath(&RootPathHandle, RootDirectory, RootPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("OpenDirectoryByHandleOrPath failed, Status 0x%08lx\n",
Status);
+ return Status;
+ }
+
+ RtlInitUnicodeString(&KeyName, RegMountPoint);
+ InitializeObjectAttributes(&KeyObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ RootKey,
+ NULL);
+
+ RtlInitUnicodeString(&FileName, RegistryKey);
+ InitializeObjectAttributes(&FileObjectAttributes,
+ &FileName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)((ULONG_PTR)RootPathHandle & ~1), // Remove
the opened-locally flag
+ NULL);
+
+ /* Mount the registry hive in the registry namespace */
+ Status = NtLoadKey(&KeyObjectAttributes, &FileObjectAttributes);
+
+ /* Close the root directory (if opened locally), and return */
+ if ((ULONG_PTR)RootPathHandle & 1) NtClose((HANDLE)((ULONG_PTR)RootPathHandle
& ~1));
+ return Status;
+}
+
+/*
+ * Should be called under privileges
+ */
+static NTSTATUS
+DisconnectRegistry(
+ IN HANDLE RootKey OPTIONAL,
+ IN PCWSTR RegMountPoint,
+ IN ULONG Flags)
+{
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ RtlInitUnicodeString(&KeyName, RegMountPoint);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ RootKey,
+ NULL);
+ // return NtUnloadKey(&ObjectAttributes);
+ return NtUnloadKey2(&ObjectAttributes, Flags);
+}
+
+
+START_TEST(NtLoadUnloadKey)
+{
+ typedef struct _HIVE_LIST_ENTRY
+ {
+ PCWSTR HiveName;
+ PCWSTR RegMountPoint;
+ } HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
+
+ static const HIVE_LIST_ENTRY RegistryHives[] =
+ {
+ { L"TestHive1", L"\\Registry\\Machine\\TestHive1" },
+ { L"TestHive2", L"\\Registry\\Machine\\TestHive2" },
+ };
+
+ NTSTATUS Status;
+ UNICODE_STRING NtTestPath;
+ UNICODE_STRING KeyName;
+ HANDLE KeyHandle;
+ ULONG Disposition;
+ UINT i;
+ BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
+ WCHAR PathBuffer[MAX_PATH];
+
+ /* Retrieve our current directory */
+ RetrieveCurrentModuleNTDirectory(&NtTestPath);
+
+ /* Acquire restore privilege */
+ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE,
&PrivilegeSet[0]);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status
0x%08lx)\n", Status);
+ /* Exit prematurely here.... */
+ // goto Cleanup;
+ RtlFreeUnicodeString(&NtTestPath);
+ return;
+ }
+
+ /* Acquire backup privilege */
+ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status
0x%08lx)\n", Status);
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE,
&PrivilegeSet[0]);
+ /* Exit prematurely here.... */
+ // goto Cleanup;
+ RtlFreeUnicodeString(&NtTestPath);
+ return;
+ }
+
+ /* Create the template proto-hive */
+ Status = CreateProtoHive(&KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ skip("CreateProtoHive() failed to create the proto-hive; Status
0x%08lx\n", Status);
+ goto Cleanup;
+ }
+
+ /* Create two registry hive files from it */
+ for (i = 0; i < _countof(RegistryHives); ++i)
+ {
+ Status = CreateRegistryFile(NULL, &NtTestPath,
+ RegistryHives[i].HiveName,
+ KeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n",
RegistryHives[i].HiveName, Status);
+ /* Exit prematurely here.... */
+ break;
+ }
+ }
+
+ /* That is now done, remove the proto-hive */
+ DestroyProtoHive(KeyHandle);
+
+ /* Exit prematurely here if we failed */
+ if (!NT_SUCCESS(Status))
+ goto Cleanup;
+
+
+/***********************************************************************************************/
+
+
+ /* Now, mount the first hive */
+ Status = ConnectRegistry(NULL, RegistryHives[0].RegMountPoint,
+ NULL, &NtTestPath,
+ RegistryHives[0].HiveName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ConnectRegistry('%wZ\\%S', '%S') failed, Status
0x%08lx\n",
+ &NtTestPath, RegistryHives[0].HiveName,
RegistryHives[0].RegMountPoint, Status);
+ }
+
+ /* Create or open a key inside the mounted hive */
+ StringCchPrintfW(PathBuffer, _countof(PathBuffer), L"%s\\%s",
RegistryHives[0].RegMountPoint, L"MyKey_1");
+ RtlInitUnicodeString(&KeyName, PathBuffer);
+
+ KeyHandle = NULL;
+ Status = CreateRegKey(&KeyHandle,
+ NULL,
+ &KeyName,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateRegKey(%wZ) failed (Status %lx)\n", &KeyName,
Status);
+ }
+ else
+ {
+ DPRINT1("CreateRegKey(%wZ) succeeded to %s the key (Status %lx)\n",
+ &KeyName,
+ Disposition == REG_CREATED_NEW_KEY ? "create" : /*
REG_OPENED_EXISTING_KEY */ "open",
+ Status);
+ }
+
+ /* The key handle must be valid here */
+ Status = NtFlushKey(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Attempt to unmount the hive, with the handle key still opened */
+ Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 0); // Same as
NtUnloadKey(&ObjectAttributes);
+ DPRINT1("Unmounting '%S' %s\n", RegistryHives[0].RegMountPoint,
NT_SUCCESS(Status) ? "succeeded" : "failed");
+ ok_ntstatus(Status, STATUS_CANNOT_DELETE);
+
+ /* The key handle should still be valid here */
+ Status = NtFlushKey(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Force-unmount the hive, with the handle key still opened */
+ Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 1 /*
REG_FORCE_UNLOAD */);
+ DPRINT1("Force-unmounting '%S' %s\n",
RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" :
"failed");
+ ok_hex(Status, STATUS_SUCCESS);
+
+ /* The key handle should not be valid anymore */
+ Status = NtFlushKey(KeyHandle);
+ if (Status != STATUS_KEY_DELETED /* Win2k3 */ &&
+ Status != STATUS_HIVE_UNLOADED /* Win7+ */)
+ {
+ ok_ntstatus(Status, STATUS_KEY_DELETED);
+ }
+
+ /* The key handle should not be valid anymore */
+ Status = NtDeleteKey(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Close by principle the handle, but should this fail? */
+ Status = NtClose(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+
+/***********************************************************************************************/
+
+
+ /* Now, mount the first hive, again */
+ Status = ConnectRegistry(NULL, RegistryHives[0].RegMountPoint,
+ NULL, &NtTestPath,
+ RegistryHives[0].HiveName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ConnectRegistry('%wZ\\%S', '%S') failed, Status
0x%08lx\n",
+ &NtTestPath, RegistryHives[0].HiveName,
RegistryHives[0].RegMountPoint, Status);
+ }
+
+ /* Create or open a key inside the mounted hive */
+ StringCchPrintfW(PathBuffer, _countof(PathBuffer), L"%s\\%s",
RegistryHives[0].RegMountPoint, L"MyKey_2");
+ RtlInitUnicodeString(&KeyName, PathBuffer);
+
+ KeyHandle = NULL;
+ Status = CreateRegKey(&KeyHandle,
+ NULL,
+ &KeyName,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CreateRegKey(%wZ) failed (Status %lx)\n", &KeyName,
Status);
+ }
+ else
+ {
+ DPRINT1("CreateRegKey(%wZ) succeeded to %s the key (Status %lx)\n",
+ &KeyName,
+ Disposition == REG_CREATED_NEW_KEY ? "create" : /*
REG_OPENED_EXISTING_KEY */ "open",
+ Status);
+ }
+
+ /* The key handle must be valid here */
+ Status = NtFlushKey(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Delete the key, this should succeed */
+ Status = NtDeleteKey(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Close the handle, this should succeed */
+ Status = NtClose(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Attempt to unmount the hive (no forcing), this should succeed */
+ Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 0); // Same as
NtUnloadKey(&ObjectAttributes);
+ DPRINT1("Unmounting '%S' %s\n", RegistryHives[0].RegMountPoint,
NT_SUCCESS(Status) ? "succeeded" : "failed");
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Force-unmount the hive (it is already unmounted), this should fail */
+ Status = DisconnectRegistry(NULL, RegistryHives[0].RegMountPoint, 1 /*
REG_FORCE_UNLOAD */);
+ DPRINT1("Force-unmounting '%S' %s\n",
RegistryHives[0].RegMountPoint, NT_SUCCESS(Status) ? "succeeded" :
"failed");
+ ok_hex(Status, STATUS_INVALID_PARAMETER);
+
+#if 0
+ /* Close by principle the handle, but should this fail? */
+ Status = NtClose(KeyHandle);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+#endif
+
+
+/***********************************************************************************************/
+
+
+Cleanup:
+
+ /* Destroy the hive files */
+ for (i = 0; i < _countof(RegistryHives); ++i)
+ {
+ Status = MyDeleteFile(NULL, &NtTestPath,
+ RegistryHives[i].HiveName, TRUE);
+ if (!NT_SUCCESS(Status))
+ DPRINT1("MyDeleteFile(%S) failed, Status 0x%08lx\n",
RegistryHives[i].HiveName, Status);
+ }
+
+ /* Remove restore and backup privileges */
+ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE,
&PrivilegeSet[1]);
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE,
&PrivilegeSet[0]);
+
+ RtlFreeUnicodeString(&NtTestPath);
+}
Propchange: trunk/rostests/apitests/ntdll/NtLoadUnloadKey.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/rostests/apitests/ntdll/testlist.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/testlist.c…
==============================================================================
--- trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] (original)
+++ trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] Sat Jun 17 20:08:48 2017
@@ -13,6 +13,7 @@
extern void func_NtCreateThread(void);
extern void func_NtDeleteKey(void);
extern void func_NtFreeVirtualMemory(void);
+extern void func_NtLoadUnloadKey(void);
extern void func_NtMapViewOfSection(void);
extern void func_NtMutant(void);
extern void func_NtOpenProcessToken(void);
@@ -68,6 +69,7 @@
{ "NtCreateThread", func_NtCreateThread },
{ "NtDeleteKey", func_NtDeleteKey },
{ "NtFreeVirtualMemory", func_NtFreeVirtualMemory },
+ { "NtLoadUnloadKey", func_NtLoadUnloadKey },
{ "NtMapViewOfSection", func_NtMapViewOfSection },
{ "NtMutant", func_NtMutant },
{ "NtOpenProcessToken", func_NtOpenProcessToken },