Module: wine Branch: master Commit: 5eb30353747303699ceb1ae99b6c33d6879721ca URL: http://source.winehq.org/git/wine.git/?a=commit;h=5eb30353747303699ceb1ae99b...
Author: Jacek Caban jacek@codeweavers.com Date: Wed Nov 11 14:17:09 2015 +0100
ntdll: Added KeyCachedInformation key info class implementation.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/reg.c | 26 +++++++++++++++++++---- dlls/ntdll/tests/reg.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- include/winternl.h | 19 ++++++++++++++++- server/registry.c | 6 +++++- 4 files changed, 101 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/reg.c b/dlls/ntdll/reg.c index 0701426..be95a2a 100644 --- a/dlls/ntdll/reg.c +++ b/dlls/ntdll/reg.c @@ -257,10 +257,11 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i
switch(info_class) { - case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break; - case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break; - case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break; - case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break; + case KeyBasicInformation: data_ptr = ((KEY_BASIC_INFORMATION *)info)->Name; break; + case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break; + case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break; + case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break; + case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break; default: FIXME( "Information class %d not implemented\n", info_class ); return STATUS_INVALID_PARAMETER; @@ -332,6 +333,23 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i memcpy( info, &keyinfo, min( length, fixed_size ) ); } break; + case KeyCachedInformation: + { + KEY_CACHED_INFORMATION keyinfo; + fixed_size = sizeof(keyinfo); + keyinfo.LastWriteTime.QuadPart = reply->modif; + keyinfo.TitleIndex = 0; + keyinfo.SubKeys = reply->subkeys; + keyinfo.MaxNameLen = reply->max_subkey; + keyinfo.Values = reply->values; + keyinfo.MaxValueNameLen = reply->max_value; + keyinfo.MaxValueDataLen = reply->max_data; + keyinfo.NameLength = reply->namelen; + memcpy( info, &keyinfo, min( length, fixed_size ) ); + } + break; + default: + break; } *result_len = fixed_size + reply->total; if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW; diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c index 149910a..dfec007 100644 --- a/dlls/ntdll/tests/reg.c +++ b/dlls/ntdll/tests/reg.c @@ -1466,12 +1466,14 @@ static void test_long_value_name(void)
static void test_NtQueryKey(void) { - HANDLE key; + HANDLE key, subkey, subkey2; NTSTATUS status; OBJECT_ATTRIBUTES attr; ULONG length, len; KEY_NAME_INFORMATION *info = NULL; + KEY_CACHED_INFORMATION cached_info; UNICODE_STRING str; + DWORD dw;
InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&key, KEY_READ, &attr); @@ -1506,6 +1508,59 @@ static void test_NtQueryKey(void) wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
HeapFree(GetProcessHeap(), 0, info); + + attr.RootDirectory = key; + attr.ObjectName = &str; + pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); + status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); + + status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); + + if (status == STATUS_SUCCESS) + { + ok(len == sizeof(cached_info), "got unexpected length %d\n", len); + ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys); + ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen); + ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values); + ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen); + ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen); + ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength); + } + + attr.RootDirectory = subkey; + attr.ObjectName = &str; + pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2"); + status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); + + pRtlCreateUnicodeStringFromAsciiz(&str, "val"); + dw = 64; + status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + + status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); + + if (status == STATUS_SUCCESS) + { + ok(len == sizeof(cached_info), "got unexpected length %d\n", len); + ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys); + ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen); + ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values); + ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen); + ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen); + ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength); + } + + status = pNtDeleteKey(subkey2); + ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); + status = pNtDeleteKey(subkey); + ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); + + pNtClose(subkey2); + pNtClose(subkey); pNtClose(key); }
diff --git a/include/winternl.h b/include/winternl.h index 1746601..ecd5791 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -696,7 +696,12 @@ typedef enum _KEY_INFORMATION_CLASS { KeyBasicInformation, KeyNodeInformation, KeyFullInformation, - KeyNameInformation + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation, + KeyVirtualizationInformation, + KeyHandleTagsInformation, + MaxKeyInfoClass } KEY_INFORMATION_CLASS;
typedef enum _KEY_VALUE_INFORMATION_CLASS { @@ -1024,6 +1029,18 @@ typedef struct _KEY_NAME_INFORMATION { WCHAR Name[1]; } KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
+typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; +} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION; + typedef struct _KEY_VALUE_ENTRY { PUNICODE_STRING ValueName; diff --git a/server/registry.c b/server/registry.c index 94777b3..dad86e7 100644 --- a/server/registry.c +++ b/server/registry.c @@ -906,6 +906,7 @@ static void enum_key( const struct key *key, int index, int info_class, reply->max_data = 0; break; case KeyFullInformation: + case KeyCachedInformation: for (i = 0; i <= key->last_subkey; i++) { if (key->subkeys[i]->namelen > max_subkey) max_subkey = key->subkeys[i]->namelen; @@ -920,7 +921,10 @@ static void enum_key( const struct key *key, int index, int info_class, reply->max_class = max_class; reply->max_value = max_value; reply->max_data = max_data; - namelen = 0; /* only return the class */ + reply->namelen = namelen; + if (info_class == KeyCachedInformation) + classlen = 0; /* don't return any data, only its size */ + namelen = 0; /* don't return name */ break; default: set_error( STATUS_INVALID_PARAMETER );