From 454355ece1966153ed1ca507f532d302192f6ef8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 2 Oct 2000 03:46:58 +0000 Subject: [PATCH] Convert NtQueryKey and NtEnumerateKey to the new request mechanism. Fixed a few bugs. --- dlls/advapi32/registry.c | 293 ++++++++++++++++++++++++++------------- dlls/ntdll/reg.c | 277 +++++++++++++++++------------------- include/ntddk.h | 8 +- include/server.h | 26 +--- memory/registry.c | 293 ++++++++++++++++++++++++++------------- server/registry.c | 186 +++++++++++++------------ server/request.h | 2 - server/trace.c | 35 ++--- 8 files changed, 637 insertions(+), 483 deletions(-) diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c index fca82b169d..26aa450971 100644 --- a/dlls/advapi32/registry.c +++ b/dlls/advapi32/registry.c @@ -289,32 +289,58 @@ DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey ) DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len, LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft ) { - DWORD ret, len, cls_len; - struct enum_key_request *req = get_req_buffer(); + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len, name_len ? *name_len : -1, reserved, class, class_len, ft ); if (reserved) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - req->index = index; - if ((ret = reg_server_call( REQ_ENUM_KEY )) != ERROR_SUCCESS) return ret; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buffer, sizeof(buffer), &total_size ); - len = strlenW( req->name ) + 1; - cls_len = strlenW( req->class ) + 1; - if (len > *name_len) return ERROR_MORE_DATA; - if (class_len && (cls_len > *class_len)) return ERROR_MORE_DATA; - - memcpy( name, req->name, len * sizeof(WCHAR) ); - *name_len = len - 1; - if (class_len) + while (status == STATUS_BUFFER_OVERFLOW) { - if (class) memcpy( class, req->class, cls_len * sizeof(WCHAR) ); - *class_len = cls_len - 1; + /* retry with a dynamically allocated buffer */ + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_NODE_INFORMATION *)buf_ptr; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buf_ptr, total_size, &total_size ); } - if (ft) RtlSecondsSince1970ToTime( req->modif, ft ); - return ERROR_SUCCESS; + + if (!status) + { + DWORD len = info->NameLength / sizeof(WCHAR); + DWORD cls_len = info->ClassLength / sizeof(WCHAR); + + if (ft) *ft = info->LastWriteTime; + + if (len >= *name_len || (class_len && (cls_len >= *class_len))) + status = STATUS_BUFFER_OVERFLOW; + else + { + *name_len = len; + memcpy( name, info->Name, info->NameLength ); + name[len] = 0; + if (class_len) + { + *class_len = cls_len; + if (class) + { + memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); + class[cls_len] = 0; + } + } + } + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -324,32 +350,64 @@ DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_le DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len, LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft ) { - DWORD ret, len, cls_len; - struct enum_key_request *req = get_req_buffer(); + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len, name_len ? *name_len : -1, reserved, class, class_len, ft ); if (reserved) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - req->index = index; - if ((ret = reg_server_call( REQ_ENUM_KEY )) != ERROR_SUCCESS) return ret; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buffer, sizeof(buffer), &total_size ); - len = strlenW( req->name ) + 1; - cls_len = strlenW( req->class ) + 1; - if (len > *name_len) return ERROR_MORE_DATA; - if (class_len && (cls_len > *class_len)) return ERROR_MORE_DATA; - - memcpyWtoA( name, req->name, len ); - *name_len = len - 1; - if (class_len) + while (status == STATUS_BUFFER_OVERFLOW) { - if (class) memcpyWtoA( class, req->class, cls_len ); - *class_len = cls_len - 1; + /* retry with a dynamically allocated buffer */ + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_NODE_INFORMATION *)buf_ptr; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buf_ptr, total_size, &total_size ); } - if (ft) RtlSecondsSince1970ToTime( req->modif, ft ); - return ERROR_SUCCESS; + + if (!status) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR), + NULL, 0, NULL, NULL ); + DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength / sizeof(WCHAR), + NULL, 0, NULL, NULL ); + + if (ft) *ft = info->LastWriteTime; + + if (len >= *name_len || (class_len && (cls_len >= *class_len))) + status = STATUS_BUFFER_OVERFLOW; + else + { + *name_len = len; + WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR), + name, len, NULL, NULL ); + name[len] = 0; + if (class_len) + { + *class_len = cls_len; + if (class) + { + WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength / sizeof(WCHAR), + class, cls_len, NULL, NULL ); + class[cls_len] = 0; + } + } + } + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -398,9 +456,10 @@ DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWO LPDWORD values, LPDWORD max_value, LPDWORD max_data, LPDWORD security, FILETIME *modif ) { - DWORD ret; - struct query_key_info_request *req = get_req_buffer(); - + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); @@ -408,27 +467,48 @@ DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWO if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/)) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - if ((ret = reg_server_call( REQ_QUERY_KEY_INFO )) != ERROR_SUCCESS) return ret; + status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); if (class) { - if (class_len && (strlenW(req->class) + 1 > *class_len)) + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) { - *class_len = strlenW(req->class); - return ERROR_MORE_DATA; + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_FULL_INFORMATION *)buf_ptr; + status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); + } + + if (!status) + { + if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len)) + { + status = STATUS_BUFFER_OVERFLOW; + } + else + { + memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); + class[info->ClassLength/sizeof(WCHAR)] = 0; + } } - strcpyW( class, req->class ); } - if (class_len) *class_len = strlenW( req->class ); - if (subkeys) *subkeys = req->subkeys; - if (max_subkey) *max_subkey = req->max_subkey; - if (max_class) *max_class = req->max_class; - if (values) *values = req->values; - if (max_value) *max_value = req->max_value; - if (max_data) *max_data = req->max_data; - if (modif) RtlSecondsSince1970ToTime( req->modif, modif ); - return ERROR_SUCCESS; + + if (!status || status == STATUS_BUFFER_OVERFLOW) + { + if (class_len) *class_len = info->ClassLength / sizeof(WCHAR); + if (subkeys) *subkeys = info->SubKeys; + if (max_subkey) *max_subkey = info->MaxNameLen; + if (max_class) *max_class = info->MaxClassLen; + if (values) *values = info->Values; + if (max_value) *max_value = info->MaxValueNameLen; + if (max_data) *max_data = info->MaxValueDataLen; + if (modif) *modif = info->LastWriteTime; + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -440,9 +520,10 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR LPDWORD values, LPDWORD max_value, LPDWORD max_data, LPDWORD security, FILETIME *modif ) { - DWORD ret; - struct query_key_info_request *req = get_req_buffer(); - + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); @@ -450,27 +531,55 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/)) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - if ((ret = reg_server_call( REQ_QUERY_KEY_INFO )) != ERROR_SUCCESS) return ret; + status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); - if (class) + if (class || class_len) { - if (class_len && (strlenW(req->class) + 1 > *class_len)) + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) { - *class_len = strlenW(req->class); - return ERROR_MORE_DATA; + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_FULL_INFORMATION *)buf_ptr; + status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); + } + + if (!status) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, + (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength/sizeof(WCHAR), + NULL, 0, NULL, NULL ); + if (class_len) + { + if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW; + *class_len = len; + } + if (class && !status) + { + WideCharToMultiByte( CP_ACP, 0, + (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength/sizeof(WCHAR), + class, len, NULL, NULL ); + class[len] = 0; + } } - lstrcpyWtoA( class, req->class ); } - if (class_len) *class_len = strlenW( req->class ); - if (subkeys) *subkeys = req->subkeys; - if (max_subkey) *max_subkey = req->max_subkey; - if (max_class) *max_class = req->max_class; - if (values) *values = req->values; - if (max_value) *max_value = req->max_value; - if (max_data) *max_data = req->max_data; - if (modif) RtlSecondsSince1970ToTime( req->modif, modif ); - return ERROR_SUCCESS; + + if (!status || status == STATUS_BUFFER_OVERFLOW) + { + if (subkeys) *subkeys = info->SubKeys; + if (max_subkey) *max_subkey = info->MaxNameLen; + if (max_class) *max_class = info->MaxClassLen; + if (values) *values = info->Values; + if (max_value) *max_value = info->MaxValueNameLen; + if (max_data) *max_data = info->MaxValueDataLen; + if (modif) *modif = info->LastWriteTime; + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -689,7 +798,7 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR NTSTATUS status; UNICODE_STRING name_str; DWORD total_size; - char buffer[256]; + char buffer[256], *buf_ptr = buffer; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; static const int info_size = sizeof(*info) - sizeof(info->Data); @@ -709,16 +818,15 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR if (data) { - char *buf_ptr = buffer; /* retry with a dynamically allocated buffer */ while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) { if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) - status = STATUS_NO_MEMORY; - else - status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, - buf_ptr, total_size, &total_size ); + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); } if (!status) @@ -732,13 +840,14 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; } } - if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + else if (status != STATUS_BUFFER_OVERFLOW) goto done; } if (type) *type = info->Type; if (count) *count = total_size - info_size; done: + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); return RtlNtStatusToDosError(status); } @@ -756,7 +865,7 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD ANSI_STRING nameA; UNICODE_STRING nameW; DWORD total_size; - char buffer[256]; + char buffer[256], *buf_ptr = buffer; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; static const int info_size = sizeof(*info) - sizeof(info->Data); @@ -767,7 +876,8 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD RtlInitAnsiString( &nameA, name ); /* FIXME: should use Unicode buffer in TEB */ - if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) goto done; + if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) + return RtlNtStatusToDosError(status); status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &total_size ); @@ -777,16 +887,18 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD * because we need to compute the length of the ASCII string. */ if (data || is_string(info->Type)) { - char *buf_ptr = buffer; /* retry with a dynamically allocated buffer */ while (status == STATUS_BUFFER_OVERFLOW) { if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + { status = STATUS_NO_MEMORY; - else - status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, - buf_ptr, total_size, &total_size ); + goto done; + } + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); } if (!status) @@ -812,23 +924,16 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD total_size = len + info_size; } else if (data) memcpy( data, buf_ptr + info_size, total_size - info_size ); - - /* if the type is REG_SZ and data is not 0-terminated - * and there is enough space in the buffer NT appends a \0 */ - if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type)) - { - WCHAR *ptr = (WCHAR *)(data + total_size - info_size); - if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; - } } - if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + else if (status != STATUS_BUFFER_OVERFLOW) goto done; } if (type) *type = info->Type; if (count) *count = total_size - info_size; - RtlFreeUnicodeString( &nameW ); done: + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + RtlFreeUnicodeString( &nameW ); return RtlNtStatusToDosError(status); } diff --git a/dlls/ntdll/reg.c b/dlls/ntdll/reg.c index 41b3005abb..c1d43eaba3 100644 --- a/dlls/ntdll/reg.c +++ b/dlls/ntdll/reg.c @@ -167,6 +167,95 @@ NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name ) } +/****************************************************************************** + * fill_key_info + * + * Helper function for NtQueryKey and NtEnumerateKey + */ +static NTSTATUS fill_key_info( KEY_INFORMATION_CLASS info_class, void *info, DWORD length, + DWORD *result_len, const struct enum_key_request *req ) +{ + WCHAR *name_ptr = server_data_ptr(req); + int name_size = *name_ptr++; + WCHAR *class_ptr = (WCHAR *)((char *)name_ptr + name_size); + int class_size = server_data_size(req) - sizeof(WCHAR) - name_size; + int fixed_size; + FILETIME modif; + + RtlSecondsSince1970ToTime( req->modif, &modif ); + + switch(info_class) + { + case KeyBasicInformation: + { + KEY_BASIC_INFORMATION keyinfo; + fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Name); + keyinfo.LastWriteTime = modif; + keyinfo.TitleIndex = 0; + keyinfo.NameLength = name_size; + memcpy( info, &keyinfo, min( length, fixed_size ) ); + class_size = 0; + } + break; + case KeyFullInformation: + { + KEY_FULL_INFORMATION keyinfo; + fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Class); + keyinfo.LastWriteTime = modif; + keyinfo.TitleIndex = 0; + keyinfo.ClassLength = class_size; + keyinfo.ClassOffset = keyinfo.ClassLength ? fixed_size : -1; + keyinfo.SubKeys = req->subkeys; + keyinfo.MaxNameLen = req->max_subkey; + keyinfo.MaxClassLen = req->max_class; + keyinfo.Values = req->values; + keyinfo.MaxValueNameLen = req->max_value; + keyinfo.MaxValueDataLen = req->max_data; + memcpy( info, &keyinfo, min( length, fixed_size ) ); + name_size = 0; + } + break; + case KeyNodeInformation: + { + KEY_NODE_INFORMATION keyinfo; + fixed_size = sizeof(keyinfo) - sizeof(keyinfo.Name); + keyinfo.LastWriteTime = modif; + keyinfo.TitleIndex = 0; + keyinfo.ClassLength = class_size; + keyinfo.ClassOffset = fixed_size + name_size; + if (!keyinfo.ClassLength || keyinfo.ClassOffset > length) keyinfo.ClassOffset = -1; + keyinfo.NameLength = name_size; + memcpy( info, &keyinfo, min( length, fixed_size ) ); + } + break; + default: + FIXME("Information class not implemented\n"); + return STATUS_INVALID_PARAMETER; + } + + *result_len = fixed_size + name_size + class_size; + if (length <= fixed_size) return STATUS_BUFFER_OVERFLOW; + length -= fixed_size; + + /* copy the name */ + if (name_size) + { + memcpy( (char *)info + fixed_size, name_ptr, min(length,name_size) ); + if (length < name_size) return STATUS_BUFFER_OVERFLOW; + length -= name_size; + } + + /* copy the class */ + if (class_size) + { + memcpy( (char *)info + fixed_size + name_size, class_ptr, min(length,class_size) ); + if (length < class_size) return STATUS_BUFFER_OVERFLOW; + } + return STATUS_SUCCESS; +} + + + /****************************************************************************** * NtEnumerateKey [NTDLL] * ZwEnumerateKey @@ -174,164 +263,52 @@ NTSTATUS WINAPI NtDeleteValueKey( HANDLE hkey, const UNICODE_STRING *name ) * NOTES * the name copied into the buffer is NOT 0-terminated */ -NTSTATUS WINAPI NtEnumerateKey( - HANDLE KeyHandle, - ULONG Index, - KEY_INFORMATION_CLASS KeyInformationClass, - PVOID KeyInformation, - ULONG Length, - PULONG ResultLength) +NTSTATUS WINAPI NtEnumerateKey( HANDLE handle, ULONG index, KEY_INFORMATION_CLASS info_class, + void *info, DWORD length, DWORD *result_len ) { - struct enum_key_request *req = get_req_buffer(); - NTSTATUS ret; + NTSTATUS ret; - TRACE("(0x%08x,0x%08lx,0x%08x,%p,0x%08lx,%p)\n", - KeyHandle, Index, KeyInformationClass, KeyInformation, Length, ResultLength); + /* -1 means query key, so avoid it here */ + if (index == (ULONG)-1) return STATUS_NO_MORE_ENTRIES; - req->hkey = KeyHandle; - req->index = Index; - if ((ret = server_call_noerr(REQ_ENUM_KEY)) != STATUS_SUCCESS) return ret; - - switch (KeyInformationClass) - { - case KeyBasicInformation: - { - PKEY_BASIC_INFORMATION kbi = KeyInformation; - UINT NameLength = strlenW(req->name) * sizeof(WCHAR); - *ResultLength = sizeof(KEY_BASIC_INFORMATION) - sizeof(WCHAR) + NameLength; - if (Length < *ResultLength) return STATUS_BUFFER_OVERFLOW; - - RtlSecondsSince1970ToTime(req->modif, &kbi->LastWriteTime); - kbi->TitleIndex = 0; - kbi->NameLength = NameLength; - memcpy (kbi->Name, req->name, NameLength); - } - break; - case KeyFullInformation: - { - PKEY_FULL_INFORMATION kfi = KeyInformation; - kfi->ClassLength = strlenW(req->class) * sizeof(WCHAR); - kfi->ClassOffset = (kfi->ClassLength) ? - sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR) : 0xffffffff; - *ResultLength = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR) + kfi->ClassLength; - if (Length < *ResultLength) return STATUS_BUFFER_OVERFLOW; - - RtlSecondsSince1970ToTime(req->modif, &kfi->LastWriteTime); - kfi->TitleIndex = 0; -/* kfi->SubKeys = req->subkeys; - kfi->MaxNameLength = req->max_subkey; - kfi->MaxClassLength = req->max_class; - kfi->Values = req->values; - kfi->MaxValueNameLen = req->max_value; - kfi->MaxValueDataLen = req->max_data; -*/ - FIXME("incomplete\n"); - if (kfi->ClassLength) memcpy (kfi->Class, req->class, kfi->ClassLength); - } - break; - case KeyNodeInformation: - { - PKEY_NODE_INFORMATION kni = KeyInformation; - kni->ClassLength = strlenW(req->class) * sizeof(WCHAR); - kni->NameLength = strlenW(req->name) * sizeof(WCHAR); - kni->ClassOffset = (kni->ClassLength) ? - sizeof(KEY_NODE_INFORMATION) - sizeof(WCHAR) + kni->NameLength : 0xffffffff; - - *ResultLength = sizeof(KEY_NODE_INFORMATION) - sizeof(WCHAR) + kni->NameLength + kni->ClassLength; - if (Length < *ResultLength) return STATUS_BUFFER_OVERFLOW; - - RtlSecondsSince1970ToTime(req->modif, &kni->LastWriteTime); - kni->TitleIndex = 0; - memcpy (kni->Name, req->name, kni->NameLength); - if (kni->ClassLength) memcpy ((char *) KeyInformation + kni->ClassOffset, req->class, kni->ClassLength); - } - break; - default: - FIXME("KeyInformationClass not implemented\n"); - return STATUS_UNSUCCESSFUL; - } - TRACE("buf=%lu len=%lu\n", Length, *ResultLength); - return ret; + SERVER_START_REQ + { + struct enum_key_request *req = server_alloc_req( sizeof(*req), REQUEST_MAX_VAR_SIZE ); + req->hkey = handle; + req->index = index; + req->full = (info_class == KeyFullInformation); + if (!(ret = server_call_noerr( REQ_ENUM_KEY ))) + { + ret = fill_key_info( info_class, info, length, result_len, req ); + } + } + SERVER_END_REQ; + return ret; } + /****************************************************************************** * NtQueryKey [NTDLL] * ZwQueryKey */ -NTSTATUS WINAPI NtQueryKey( - HANDLE KeyHandle, - KEY_INFORMATION_CLASS KeyInformationClass, - PVOID KeyInformation, - ULONG Length, - PULONG ResultLength) +NTSTATUS WINAPI NtQueryKey( HANDLE handle, KEY_INFORMATION_CLASS info_class, + void *info, DWORD length, DWORD *result_len ) { - struct query_key_info_request *req = get_req_buffer(); - NTSTATUS ret; - - TRACE("(0x%08x,0x%08x,%p,0x%08lx,%p) stub\n", - KeyHandle, KeyInformationClass, KeyInformation, Length, ResultLength); - - req->hkey = KeyHandle; - if ((ret = server_call_noerr(REQ_QUERY_KEY_INFO)) != STATUS_SUCCESS) return ret; - - switch (KeyInformationClass) - { - case KeyBasicInformation: - { - PKEY_BASIC_INFORMATION kbi = KeyInformation; - UINT NameLength = strlenW(req->name) * sizeof(WCHAR); - *ResultLength = sizeof(KEY_BASIC_INFORMATION) - sizeof(WCHAR) + NameLength; - if (Length < *ResultLength) return STATUS_BUFFER_OVERFLOW; + NTSTATUS ret; - RtlSecondsSince1970ToTime(req->modif, &kbi->LastWriteTime); - kbi->TitleIndex = 0; - kbi->NameLength = NameLength; - memcpy (kbi->Name, req->name, NameLength); - } - break; - case KeyFullInformation: - { - PKEY_FULL_INFORMATION kfi = KeyInformation; - kfi->ClassLength = strlenW(req->class) * sizeof(WCHAR); - kfi->ClassOffset = (kfi->ClassLength) ? - sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR) : 0xffffffff; - - *ResultLength = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR) + kfi->ClassLength; - if (Length < *ResultLength) return STATUS_BUFFER_OVERFLOW; - - RtlSecondsSince1970ToTime(req->modif, &kfi->LastWriteTime); - kfi->TitleIndex = 0; - kfi->SubKeys = req->subkeys; - kfi->MaxNameLen = req->max_subkey; - kfi->MaxClassLen = req->max_class; - kfi->Values = req->values; - kfi->MaxValueNameLen = req->max_value; - kfi->MaxValueDataLen = req->max_data; - if(kfi->ClassLength) memcpy ((char *) KeyInformation + kfi->ClassOffset, req->class, kfi->ClassLength); - } - break; - case KeyNodeInformation: - { - PKEY_NODE_INFORMATION kni = KeyInformation; - kni->ClassLength = strlenW(req->class) * sizeof(WCHAR); - kni->NameLength = strlenW(req->name) * sizeof(WCHAR); - kni->ClassOffset = (kni->ClassLength) ? - sizeof(KEY_NODE_INFORMATION) - sizeof(WCHAR) + kni->NameLength : 0xffffffff; - - *ResultLength = sizeof(KEY_NODE_INFORMATION) - sizeof(WCHAR) + kni->NameLength + kni->ClassLength; - if (Length < *ResultLength) return STATUS_BUFFER_OVERFLOW; - - RtlSecondsSince1970ToTime(req->modif, &kni->LastWriteTime); - kni->TitleIndex = 0; - memcpy (kni->Name, req->name, kni->NameLength); - if(kni->ClassLength) memcpy ((char *) KeyInformation + kni->ClassOffset, req->class, kni->ClassLength); - } - break; - default: - FIXME("KeyInformationClass not implemented\n"); - return STATUS_UNSUCCESSFUL; - } - return ret; + SERVER_START_REQ + { + struct enum_key_request *req = server_alloc_req( sizeof(*req), REQUEST_MAX_VAR_SIZE ); + req->hkey = handle; + req->index = -1; + req->full = (info_class == KeyFullInformation); + if (!(ret = server_call_noerr( REQ_ENUM_KEY ))) + { + ret = fill_key_info( info_class, info, length, result_len, req ); + } + } + SERVER_END_REQ; + return ret; } /****************************************************************************** @@ -489,8 +466,6 @@ NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name, KEY_VALUE_INFORMATION_CLASS info_class, void *info, DWORD length, DWORD *result_len ) { - - NTSTATUS ret; char *data_ptr; int fixed_size = 0, data_len = 0, offset = 0, type = 0, total_len = 0; @@ -523,7 +498,7 @@ NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name, do { size_t reqlen = min( data_len, REQUEST_MAX_VAR_SIZE ); - reqlen = max( reqlen, name->Length ); + reqlen = max( reqlen, name->Length + sizeof(WCHAR) ); SERVER_START_REQ { @@ -554,7 +529,7 @@ NTSTATUS WINAPI NtQueryValueKey( HANDLE handle, const UNICODE_STRING *name, *result_len = total_len + fixed_size; - if (!data_len) ret = STATUS_BUFFER_OVERFLOW; + if (offset < total_len) ret = STATUS_BUFFER_OVERFLOW; if (length < fixed_size) ret = STATUS_BUFFER_OVERFLOW; switch(info_class) diff --git a/include/ntddk.h b/include/ntddk.h index 8aef5cb11b..aefc99e66b 100644 --- a/include/ntddk.h +++ b/include/ntddk.h @@ -821,17 +821,11 @@ NTSTATUS WINAPI NtDeleteKey(HANDLE); NTSTATUS WINAPI NtDeleteValueKey(HANDLE,const UNICODE_STRING*); NTSTATUS WINAPI NtOpenKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*); NTSTATUS WINAPI NtSetValueKey(HANDLE,const UNICODE_STRING*,ULONG,ULONG,const void*,ULONG); +NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void*,DWORD,DWORD*); NTSTATUS WINAPI NtQueryValueKey(HANDLE,const UNICODE_STRING*,KEY_VALUE_INFORMATION_CLASS, void*,DWORD,DWORD*); -NTSTATUS WINAPI NtEnumerateKey( - HANDLE KeyHandle, - ULONG Index, - KEY_INFORMATION_CLASS KeyInformationClass, - PVOID KeyInformation, - ULONG Length, - PULONG ResultLength); NTSTATUS WINAPI NtQueryKey( HANDLE KeyHandle, diff --git a/include/server.h b/include/server.h index f9255fe962..443c547700 100644 --- a/include/server.h +++ b/include/server.h @@ -1046,18 +1046,8 @@ struct enum_key_request { REQUEST_HEADER; /* request header */ IN int hkey; /* handle to registry key */ - IN int index; /* index of subkey */ - OUT time_t modif; /* last modification time */ - OUT path_t name; /* subkey name */ - OUT WCHAR class[1]; /* class name */ -}; - - -/* Query information about a registry key */ -struct query_key_info_request -{ - REQUEST_HEADER; /* request header */ - IN int hkey; /* handle to registry key */ + IN int index; /* index of subkey (or -1 for current key) */ + IN int full; /* return the full info? */ OUT int subkeys; /* number of subkeys */ OUT int max_subkey; /* longest subkey name */ OUT int max_class; /* longest class name */ @@ -1065,8 +1055,8 @@ struct query_key_info_request OUT int max_value; /* longest value name */ OUT int max_data; /* longest value data */ OUT time_t modif; /* last modification time */ - OUT path_t name; /* key name */ - OUT WCHAR class[1]; /* class name */ + OUT VARARG(name,unicode_len_str); /* key name */ + OUT VARARG(class,unicode_str); /* class name */ }; @@ -1429,7 +1419,6 @@ enum request REQ_OPEN_KEY, REQ_DELETE_KEY, REQ_ENUM_KEY, - REQ_QUERY_KEY_INFO, REQ_SET_KEY_VALUE, REQ_GET_KEY_VALUE, REQ_ENUM_KEY_VALUE, @@ -1545,7 +1534,6 @@ union generic_request struct open_key_request open_key; struct delete_key_request delete_key; struct enum_key_request enum_key; - struct query_key_info_request query_key_info; struct set_key_value_request set_key_value; struct get_key_value_request get_key_value; struct enum_key_value_request enum_key_value; @@ -1574,7 +1562,7 @@ union generic_request struct set_serial_info_request set_serial_info; }; -#define SERVER_PROTOCOL_VERSION 24 +#define SERVER_PROTOCOL_VERSION 25 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ @@ -1648,13 +1636,13 @@ static inline void server_strcpyAtoW( WCHAR *dst, const char *src ) } /* get a pointer to the variable part of the request */ -inline static void *server_data_ptr( void *req ) +inline static void *server_data_ptr( const void *req ) { return (union generic_request *)req + 1; } /* get the size of the variable part of the request */ -inline static size_t server_data_size( void *req ) +inline static size_t server_data_size( const void *req ) { return ((struct request_header *)req)->var_size; } diff --git a/memory/registry.c b/memory/registry.c index fca82b169d..26aa450971 100644 --- a/memory/registry.c +++ b/memory/registry.c @@ -289,32 +289,58 @@ DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, LPHKEY retkey ) DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_len, LPDWORD reserved, LPWSTR class, LPDWORD class_len, FILETIME *ft ) { - DWORD ret, len, cls_len; - struct enum_key_request *req = get_req_buffer(); + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len, name_len ? *name_len : -1, reserved, class, class_len, ft ); if (reserved) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - req->index = index; - if ((ret = reg_server_call( REQ_ENUM_KEY )) != ERROR_SUCCESS) return ret; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buffer, sizeof(buffer), &total_size ); - len = strlenW( req->name ) + 1; - cls_len = strlenW( req->class ) + 1; - if (len > *name_len) return ERROR_MORE_DATA; - if (class_len && (cls_len > *class_len)) return ERROR_MORE_DATA; - - memcpy( name, req->name, len * sizeof(WCHAR) ); - *name_len = len - 1; - if (class_len) + while (status == STATUS_BUFFER_OVERFLOW) { - if (class) memcpy( class, req->class, cls_len * sizeof(WCHAR) ); - *class_len = cls_len - 1; + /* retry with a dynamically allocated buffer */ + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_NODE_INFORMATION *)buf_ptr; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buf_ptr, total_size, &total_size ); } - if (ft) RtlSecondsSince1970ToTime( req->modif, ft ); - return ERROR_SUCCESS; + + if (!status) + { + DWORD len = info->NameLength / sizeof(WCHAR); + DWORD cls_len = info->ClassLength / sizeof(WCHAR); + + if (ft) *ft = info->LastWriteTime; + + if (len >= *name_len || (class_len && (cls_len >= *class_len))) + status = STATUS_BUFFER_OVERFLOW; + else + { + *name_len = len; + memcpy( name, info->Name, info->NameLength ); + name[len] = 0; + if (class_len) + { + *class_len = cls_len; + if (class) + { + memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); + class[cls_len] = 0; + } + } + } + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -324,32 +350,64 @@ DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD index, LPWSTR name, LPDWORD name_le DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD index, LPSTR name, LPDWORD name_len, LPDWORD reserved, LPSTR class, LPDWORD class_len, FILETIME *ft ) { - DWORD ret, len, cls_len; - struct enum_key_request *req = get_req_buffer(); + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n", hkey, index, name, name_len, name_len ? *name_len : -1, reserved, class, class_len, ft ); if (reserved) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - req->index = index; - if ((ret = reg_server_call( REQ_ENUM_KEY )) != ERROR_SUCCESS) return ret; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buffer, sizeof(buffer), &total_size ); - len = strlenW( req->name ) + 1; - cls_len = strlenW( req->class ) + 1; - if (len > *name_len) return ERROR_MORE_DATA; - if (class_len && (cls_len > *class_len)) return ERROR_MORE_DATA; - - memcpyWtoA( name, req->name, len ); - *name_len = len - 1; - if (class_len) + while (status == STATUS_BUFFER_OVERFLOW) { - if (class) memcpyWtoA( class, req->class, cls_len ); - *class_len = cls_len - 1; + /* retry with a dynamically allocated buffer */ + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_NODE_INFORMATION *)buf_ptr; + status = NtEnumerateKey( hkey, index, KeyNodeInformation, + buf_ptr, total_size, &total_size ); } - if (ft) RtlSecondsSince1970ToTime( req->modif, ft ); - return ERROR_SUCCESS; + + if (!status) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR), + NULL, 0, NULL, NULL ); + DWORD cls_len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength / sizeof(WCHAR), + NULL, 0, NULL, NULL ); + + if (ft) *ft = info->LastWriteTime; + + if (len >= *name_len || (class_len && (cls_len >= *class_len))) + status = STATUS_BUFFER_OVERFLOW; + else + { + *name_len = len; + WideCharToMultiByte( CP_ACP, 0, info->Name, info->NameLength/sizeof(WCHAR), + name, len, NULL, NULL ); + name[len] = 0; + if (class_len) + { + *class_len = cls_len; + if (class) + { + WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength / sizeof(WCHAR), + class, cls_len, NULL, NULL ); + class[cls_len] = 0; + } + } + } + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -398,9 +456,10 @@ DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWO LPDWORD values, LPDWORD max_value, LPDWORD max_data, LPDWORD security, FILETIME *modif ) { - DWORD ret; - struct query_key_info_request *req = get_req_buffer(); - + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); @@ -408,27 +467,48 @@ DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR class, LPDWORD class_len, LPDWO if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/)) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - if ((ret = reg_server_call( REQ_QUERY_KEY_INFO )) != ERROR_SUCCESS) return ret; + status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); if (class) { - if (class_len && (strlenW(req->class) + 1 > *class_len)) + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) { - *class_len = strlenW(req->class); - return ERROR_MORE_DATA; + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_FULL_INFORMATION *)buf_ptr; + status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); + } + + if (!status) + { + if (class_len && (info->ClassLength/sizeof(WCHAR) + 1 > *class_len)) + { + status = STATUS_BUFFER_OVERFLOW; + } + else + { + memcpy( class, buf_ptr + info->ClassOffset, info->ClassLength ); + class[info->ClassLength/sizeof(WCHAR)] = 0; + } } - strcpyW( class, req->class ); } - if (class_len) *class_len = strlenW( req->class ); - if (subkeys) *subkeys = req->subkeys; - if (max_subkey) *max_subkey = req->max_subkey; - if (max_class) *max_class = req->max_class; - if (values) *values = req->values; - if (max_value) *max_value = req->max_value; - if (max_data) *max_data = req->max_data; - if (modif) RtlSecondsSince1970ToTime( req->modif, modif ); - return ERROR_SUCCESS; + + if (!status || status == STATUS_BUFFER_OVERFLOW) + { + if (class_len) *class_len = info->ClassLength / sizeof(WCHAR); + if (subkeys) *subkeys = info->SubKeys; + if (max_subkey) *max_subkey = info->MaxNameLen; + if (max_class) *max_class = info->MaxClassLen; + if (values) *values = info->Values; + if (max_value) *max_value = info->MaxValueNameLen; + if (max_data) *max_data = info->MaxValueDataLen; + if (modif) *modif = info->LastWriteTime; + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -440,9 +520,10 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR LPDWORD values, LPDWORD max_value, LPDWORD max_data, LPDWORD security, FILETIME *modif ) { - DWORD ret; - struct query_key_info_request *req = get_req_buffer(); - + NTSTATUS status; + char buffer[256], *buf_ptr = buffer; + KEY_FULL_INFORMATION *info = (KEY_FULL_INFORMATION *)buffer; + DWORD total_size; TRACE( "(0x%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n", hkey, class, class_len ? *class_len : 0, reserved, subkeys, max_subkey, values, max_value, max_data, security, modif ); @@ -450,27 +531,55 @@ DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDWOR if (class && !class_len && !(GetVersion() & 0x80000000 /*NT*/)) return ERROR_INVALID_PARAMETER; - req->hkey = hkey; - if ((ret = reg_server_call( REQ_QUERY_KEY_INFO )) != ERROR_SUCCESS) return ret; + status = NtQueryKey( hkey, KeyFullInformation, buffer, sizeof(buffer), &total_size ); - if (class) + if (class || class_len) { - if (class_len && (strlenW(req->class) + 1 > *class_len)) + /* retry with a dynamically allocated buffer */ + while (status == STATUS_BUFFER_OVERFLOW) { - *class_len = strlenW(req->class); - return ERROR_MORE_DATA; + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_FULL_INFORMATION *)buf_ptr; + status = NtQueryKey( hkey, KeyFullInformation, buf_ptr, total_size, &total_size ); + } + + if (!status) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, + (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength/sizeof(WCHAR), + NULL, 0, NULL, NULL ); + if (class_len) + { + if (len + 1 > *class_len) status = STATUS_BUFFER_OVERFLOW; + *class_len = len; + } + if (class && !status) + { + WideCharToMultiByte( CP_ACP, 0, + (WCHAR *)(buf_ptr + info->ClassOffset), + info->ClassLength/sizeof(WCHAR), + class, len, NULL, NULL ); + class[len] = 0; + } } - lstrcpyWtoA( class, req->class ); } - if (class_len) *class_len = strlenW( req->class ); - if (subkeys) *subkeys = req->subkeys; - if (max_subkey) *max_subkey = req->max_subkey; - if (max_class) *max_class = req->max_class; - if (values) *values = req->values; - if (max_value) *max_value = req->max_value; - if (max_data) *max_data = req->max_data; - if (modif) RtlSecondsSince1970ToTime( req->modif, modif ); - return ERROR_SUCCESS; + + if (!status || status == STATUS_BUFFER_OVERFLOW) + { + if (subkeys) *subkeys = info->SubKeys; + if (max_subkey) *max_subkey = info->MaxNameLen; + if (max_class) *max_class = info->MaxClassLen; + if (values) *values = info->Values; + if (max_value) *max_value = info->MaxValueNameLen; + if (max_data) *max_data = info->MaxValueDataLen; + if (modif) *modif = info->LastWriteTime; + } + + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + return RtlNtStatusToDosError( status ); } @@ -689,7 +798,7 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR NTSTATUS status; UNICODE_STRING name_str; DWORD total_size; - char buffer[256]; + char buffer[256], *buf_ptr = buffer; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; static const int info_size = sizeof(*info) - sizeof(info->Data); @@ -709,16 +818,15 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR if (data) { - char *buf_ptr = buffer; /* retry with a dynamically allocated buffer */ while (status == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *count) { if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) - status = STATUS_NO_MEMORY; - else - status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, - buf_ptr, total_size, &total_size ); + return ERROR_NOT_ENOUGH_MEMORY; + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &name_str, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); } if (!status) @@ -732,13 +840,14 @@ DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDWOR if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; } } - if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + else if (status != STATUS_BUFFER_OVERFLOW) goto done; } if (type) *type = info->Type; if (count) *count = total_size - info_size; done: + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); return RtlNtStatusToDosError(status); } @@ -756,7 +865,7 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD ANSI_STRING nameA; UNICODE_STRING nameW; DWORD total_size; - char buffer[256]; + char buffer[256], *buf_ptr = buffer; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; static const int info_size = sizeof(*info) - sizeof(info->Data); @@ -767,7 +876,8 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD RtlInitAnsiString( &nameA, name ); /* FIXME: should use Unicode buffer in TEB */ - if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) goto done; + if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) + return RtlNtStatusToDosError(status); status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &total_size ); @@ -777,16 +887,18 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD * because we need to compute the length of the ASCII string. */ if (data || is_string(info->Type)) { - char *buf_ptr = buffer; /* retry with a dynamically allocated buffer */ while (status == STATUS_BUFFER_OVERFLOW) { if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size ))) + { status = STATUS_NO_MEMORY; - else - status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, - buf_ptr, total_size, &total_size ); + goto done; + } + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); } if (!status) @@ -812,23 +924,16 @@ DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD total_size = len + info_size; } else if (data) memcpy( data, buf_ptr + info_size, total_size - info_size ); - - /* if the type is REG_SZ and data is not 0-terminated - * and there is enough space in the buffer NT appends a \0 */ - if (total_size - info_size <= *count-sizeof(WCHAR) && is_string(info->Type)) - { - WCHAR *ptr = (WCHAR *)(data + total_size - info_size); - if (ptr > (WCHAR *)data && ptr[-1]) *ptr = 0; - } } - if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + else if (status != STATUS_BUFFER_OVERFLOW) goto done; } if (type) *type = info->Type; if (count) *count = total_size - info_size; - RtlFreeUnicodeString( &nameW ); done: + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + RtlFreeUnicodeString( &nameW ); return RtlNtStatusToDosError(status); } diff --git a/server/registry.c b/server/registry.c index 8d355c57fb..944d7312e1 100644 --- a/server/registry.c +++ b/server/registry.c @@ -560,57 +560,80 @@ static struct key *create_key( struct key *key, WCHAR *name, WCHAR *class, return key; } -/* find a subkey of a given key by its index */ -static void enum_key( struct key *parent, int index, WCHAR *name, WCHAR *class, time_t *modif ) +/* query information about a key or a subkey */ +static size_t enum_key( struct key *key, int index, struct enum_key_request *req ) { - struct key *key; - - if ((index < 0) || (index > parent->last_subkey)) set_error( STATUS_NO_MORE_ENTRIES ); - else - { - key = parent->subkeys[index]; - *modif = key->modif; - strcpyW( name, key->name ); - if (key->class) strcpyW( class, key->class ); /* FIXME: length */ - else *class = 0; - if (debug_level > 1) dump_operation( key, NULL, "Enum" ); - } -} - -/* query information about a key */ -static void query_key( struct key *key, struct query_key_info_request *req ) -{ - int i, len; + int i; + size_t len, namelen, classlen; int max_subkey = 0, max_class = 0; int max_value = 0, max_data = 0; + WCHAR *data = get_req_data(req); - for (i = 0; i <= key->last_subkey; i++) + if (index != -1) /* -1 means use the specified key directly */ { - struct key *subkey = key->subkeys[i]; - len = strlenW( subkey->name ); - if (len > max_subkey) max_subkey = len; - if (!subkey->class) continue; - len = strlenW( subkey->class ); - if (len > max_class) max_class = len; + if ((index < 0) || (index > key->last_subkey)) + { + set_error( STATUS_NO_MORE_ENTRIES ); + return 0; + } + key = key->subkeys[index]; } - for (i = 0; i <= key->last_value; i++) + + if (req->full) { - len = strlenW( key->values[i].name ); - if (len > max_value) max_value = len; - len = key->values[i].len; - if (len > max_data) max_data = len; + for (i = 0; i <= key->last_subkey; i++) + { + struct key *subkey = key->subkeys[i]; + len = strlenW( subkey->name ); + if (len > max_subkey) max_subkey = len; + if (!subkey->class) continue; + len = strlenW( subkey->class ); + if (len > max_class) max_class = len; + } + for (i = 0; i <= key->last_value; i++) + { + len = strlenW( key->values[i].name ); + if (len > max_value) max_value = len; + len = key->values[i].len; + if (len > max_data) max_data = len; + } + req->max_subkey = max_subkey; + req->max_class = max_class; + req->max_value = max_value; + req->max_data = max_data; } - req->subkeys = key->last_subkey + 1; - req->max_subkey = max_subkey; - req->max_class = max_class; - req->values = key->last_value + 1; - req->max_value = max_value; - req->max_data = max_data; - req->modif = key->modif; - strcpyW( req->name, key->name); - if (key->class) strcpyW( req->class, key->class ); /* FIXME: length */ - else req->class[0] = 0; - if (debug_level > 1) dump_operation( key, NULL, "Query" ); + else + { + req->max_subkey = 0; + req->max_class = 0; + req->max_value = 0; + req->max_data = 0; + } + req->subkeys = key->last_subkey + 1; + req->values = key->last_value + 1; + req->modif = key->modif; + + namelen = strlenW(key->name) * sizeof(WCHAR); + classlen = key->class ? strlenW(key->class) * sizeof(WCHAR) : 0; + + len = namelen + classlen + sizeof(WCHAR); + if (len > get_req_data_size(req)) + { + len = get_req_data_size(req); + if (len < sizeof(WCHAR)) return 0; + } + + *data++ = namelen; + len -= sizeof(WCHAR); + if (len > namelen) + { + memcpy( data, key->name, namelen ); + memcpy( (char *)data + namelen, key->class, min(classlen,len-namelen) ); + } + else memcpy( data, key->name, len ); + + if (debug_level > 1) dump_operation( key, NULL, "Enum" ); + return len + sizeof(WCHAR); } /* delete a key and its values */ @@ -1537,31 +1560,29 @@ DECL_HANDLER(create_key) if (access & MAXIMUM_ALLOWED) access = KEY_ALL_ACCESS; /* FIXME: needs general solution */ req->hkey = -1; + if (!(name = copy_req_path( req, &len ))) return; if ((parent = get_hkey_obj( req->parent, 0 /*FIXME*/ ))) { - if ((name = copy_req_path( req, &len ))) + if (len == get_req_data_size(req)) /* no class specified */ { - if (len == get_req_data_size(req)) /* no class specified */ - { - key = create_key( parent, name, NULL, req->options, req->modif, &req->created ); - } - else - { - const WCHAR *class_ptr = (WCHAR *)((char *)get_req_data(req) + len); + key = create_key( parent, name, NULL, req->options, req->modif, &req->created ); + } + else + { + const WCHAR *class_ptr = (WCHAR *)((char *)get_req_data(req) + len); - if ((class = req_strdupW( req, class_ptr, get_req_data_size(req) - len ))) - { - key = create_key( parent, name, class, req->options, - req->modif, &req->created ); - free( class ); - } - } - if (key) + if ((class = req_strdupW( req, class_ptr, get_req_data_size(req) - len ))) { - req->hkey = alloc_handle( current->process, key, access, 0 ); - release_object( key ); + key = create_key( parent, name, class, req->options, + req->modif, &req->created ); + free( class ); } } + if (key) + { + req->hkey = alloc_handle( current->process, key, access, 0 ); + release_object( key ); + } release_object( parent ); } } @@ -1602,26 +1623,15 @@ DECL_HANDLER(delete_key) DECL_HANDLER(enum_key) { struct key *key; + size_t len = 0; - req->name[0] = req->class[0] = 0; - if ((key = get_hkey_obj( req->hkey, KEY_ENUMERATE_SUB_KEYS ))) + if ((key = get_hkey_obj( req->hkey, + req->index == -1 ? KEY_QUERY_VALUE : KEY_ENUMERATE_SUB_KEYS ))) { - enum_key( key, req->index, req->name, req->class, &req->modif ); - release_object( key ); - } -} - -/* query information about a registry key */ -DECL_HANDLER(query_key_info) -{ - struct key *key; - - req->name[0] = req->class[0] = 0; - if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE ))) - { - query_key( key, req ); + len = enum_key( key, req->index, req ); release_object( key ); } + set_req_data_size( req, len ); } /* set a value of a registry key */ @@ -1631,15 +1641,13 @@ DECL_HANDLER(set_key_value) WCHAR *name; size_t len; + if (!(name = copy_req_path( req, &len ))) return; if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE ))) { - if ((name = copy_req_path( req, &len ))) - { - size_t datalen = get_req_data_size(req) - len; - const char *data = (char *)get_req_data(req) + len; + size_t datalen = get_req_data_size(req) - len; + const char *data = (char *)get_req_data(req) + len; - set_value( key, name, req->type, req->total, req->offset, datalen, data ); - } + set_value( key, name, req->type, req->total, req->offset, datalen, data ); release_object( key ); } } @@ -1649,19 +1657,17 @@ DECL_HANDLER(get_key_value) { struct key *key; WCHAR *name; - size_t len; + size_t len = 0, tmp; req->len = 0; + if (!(name = copy_req_path( req, &tmp ))) return; if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE ))) { - if ((name = copy_req_path( req, &len ))) - { - len = get_value( key, name, req->offset, get_req_data_size(req), - &req->type, &req->len, get_req_data(req) ); - set_req_data_size( req, len ); - } + len = get_value( key, name, req->offset, get_req_data_size(req), + &req->type, &req->len, get_req_data(req) ); release_object( key ); } + set_req_data_size( req, len ); } /* enumerate the value of a registry key */ diff --git a/server/request.h b/server/request.h index 738b4d070c..ac80b7bbcc 100644 --- a/server/request.h +++ b/server/request.h @@ -176,7 +176,6 @@ DECL_HANDLER(create_key); DECL_HANDLER(open_key); DECL_HANDLER(delete_key); DECL_HANDLER(enum_key); -DECL_HANDLER(query_key_info); DECL_HANDLER(set_key_value); DECL_HANDLER(get_key_value); DECL_HANDLER(enum_key_value); @@ -291,7 +290,6 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_open_key, (req_handler)req_delete_key, (req_handler)req_enum_key, - (req_handler)req_query_key_info, (req_handler)req_set_key_value, (req_handler)req_get_key_value, (req_handler)req_enum_key_value, diff --git a/server/trace.c b/server/trace.c index bc3e4ff491..b9e02a8135 100644 --- a/server/trace.c +++ b/server/trace.c @@ -94,7 +94,7 @@ static void dump_exc_record( const EXCEPTION_RECORD *rec ) fprintf( stderr, "{code=%lx,flags=%lx,rec=%p,addr=%p,params={", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionRecord, rec->ExceptionAddress ); - for (i = 0; i < rec->NumberParameters; i++) + for (i = 0; i < min(rec->NumberParameters,EXCEPTION_MAXIMUM_PARAMETERS); i++) { if (i) fputc( ',', stderr ); fprintf( stderr, "%lx", rec->ExceptionInformation[i] ); @@ -156,12 +156,12 @@ static size_t dump_varargs_string( const void *req ) static size_t dump_varargs_unicode_len_str( const void *req ) { const WCHAR *str = get_data(req); - WCHAR len = *str++; + int len = *str++ + sizeof(WCHAR); len = min( len, get_size(req) ); fprintf( stderr, "L\"" ); - dump_strW( str, len / sizeof(WCHAR), stderr, "\"\"" ); + if (len >= sizeof(WCHAR)) dump_strW( str, (len / sizeof(WCHAR)) - 1, stderr, "\"\"" ); fputc( '\"', stderr ); - return len + sizeof(WCHAR); + return len; } static size_t dump_varargs_unicode_str( const void *req ) @@ -1184,25 +1184,11 @@ static void dump_delete_key_request( const struct delete_key_request *req ) static void dump_enum_key_request( const struct enum_key_request *req ) { fprintf( stderr, " hkey=%d,", req->hkey ); - fprintf( stderr, " index=%d", req->index ); + fprintf( stderr, " index=%d,", req->index ); + fprintf( stderr, " full=%d", req->full ); } static void dump_enum_key_reply( const struct enum_key_request *req ) -{ - fprintf( stderr, " modif=%ld,", req->modif ); - fprintf( stderr, " name=" ); - dump_path_t( req, &req->name ); - fprintf( stderr, "," ); - fprintf( stderr, " class=" ); - dump_unicode_string( req, req->class ); -} - -static void dump_query_key_info_request( const struct query_key_info_request *req ) -{ - fprintf( stderr, " hkey=%d", req->hkey ); -} - -static void dump_query_key_info_reply( const struct query_key_info_request *req ) { fprintf( stderr, " subkeys=%d,", req->subkeys ); fprintf( stderr, " max_subkey=%d,", req->max_subkey ); @@ -1212,10 +1198,10 @@ static void dump_query_key_info_reply( const struct query_key_info_request *req fprintf( stderr, " max_data=%d,", req->max_data ); fprintf( stderr, " modif=%ld,", req->modif ); fprintf( stderr, " name=" ); - dump_path_t( req, &req->name ); - fprintf( stderr, "," ); + cur_pos += dump_varargs_unicode_len_str( req ); + fputc( ',', stderr ); fprintf( stderr, " class=" ); - dump_unicode_string( req, req->class ); + cur_pos += dump_varargs_unicode_str( req ); } static void dump_set_key_value_request( const struct set_key_value_request *req ) @@ -1574,7 +1560,6 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_open_key_request, (dump_func)dump_delete_key_request, (dump_func)dump_enum_key_request, - (dump_func)dump_query_key_info_request, (dump_func)dump_set_key_value_request, (dump_func)dump_get_key_value_request, (dump_func)dump_enum_key_value_request, @@ -1686,7 +1671,6 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_open_key_reply, (dump_func)0, (dump_func)dump_enum_key_reply, - (dump_func)dump_query_key_info_reply, (dump_func)0, (dump_func)dump_get_key_value_reply, (dump_func)dump_enum_key_value_reply, @@ -1798,7 +1782,6 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "open_key", "delete_key", "enum_key", - "query_key_info", "set_key_value", "get_key_value", "enum_key_value",