From 52ce60c8d8f28112ae919b9faf065bcdf4d41ff1 Mon Sep 17 00:00:00 2001 From: Rafal Harabien Date: Sun, 10 Apr 2011 21:24:49 +0000 Subject: [PATCH] [ADVAPI32] * Copy RegQueryValueExA from Wine. Fixes 24 winetests fails which appeared after r51222. They are caused by calling RegQueryValueExA with buffer size set to large value. Old implementation was allocating new buffer with specified size (it was failing) and using unicode function. New implementation use given buffer size only when coping data. See issue #6105 for more details. svn path=/trunk/; revision=51314 --- reactos/dll/win32/advapi32/reg/reg.c | 187 +++++++++++++-------------- 1 file changed, 93 insertions(+), 94 deletions(-) diff --git a/reactos/dll/win32/advapi32/reg/reg.c b/reactos/dll/win32/advapi32/reg/reg.c index cfc8ba1ea28..6f79ea466fc 100644 --- a/reactos/dll/win32/advapi32/reg/reg.c +++ b/reactos/dll/win32/advapi32/reg/reg.c @@ -3974,128 +3974,127 @@ RegQueryReflectionKey(IN HKEY hBase, } -/************************************************************************ - * RegQueryValueExA +/****************************************************************************** + * RegQueryValueExA [ADVAPI32.@] * - * @implemented + * Get the type and contents of a specified value under with a key. + * + * PARAMS + * hkey [I] Handle of the key to query + * name [I] Name of value under hkey to query + * reserved [I] Reserved - must be NULL + * type [O] Destination for the value type, or NULL if not required + * data [O] Destination for the values contents, or NULL if not required + * count [I/O] Size of data, updated with the number of bytes returned + * + * RETURNS + * Success: ERROR_SUCCESS. *count is updated with the number of bytes copied to data. + * Failure: ERROR_INVALID_HANDLE, if hkey is invalid. + * ERROR_INVALID_PARAMETER, if any other parameter is invalid. + * ERROR_MORE_DATA, if on input *count is too small to hold the contents. + * + * NOTES + * MSDN states that if data is too small it is partially filled. In reality + * it remains untouched. */ -LONG WINAPI -RegQueryValueExA(HKEY hKey, - LPCSTR lpValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData) +LONG +WINAPI +RegQueryValueExA(HKEY hkeyorg, + LPCSTR name, + LPDWORD reserved, + LPDWORD type, + LPBYTE data, + LPDWORD count) { - UNICODE_STRING ValueName; - LPWSTR lpValueBuffer; - LONG ErrorCode; - DWORD Length; - DWORD Type; - NTSTATUS Status; - ULONG Index; + HANDLE hkey; + NTSTATUS status; + ANSI_STRING nameA; + UNICODE_STRING nameW; + DWORD total_size, datalen = 0; + char buffer[256], *buf_ptr = buffer; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; + static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); - TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n", - hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0); + TRACE("(%p,%s,%p,%p,%p,%p=%d)\n", + hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); - if (lpData != NULL && lpcbData == NULL) + if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; + status = MapDefaultKey(&hkey, hkeyorg); + if (!NT_SUCCESS(status)) { - return ERROR_INVALID_PARAMETER; + return RtlNtStatusToDosError(status); } - Length = (lpcbData == NULL || lpData == NULL) ? 0 : *lpcbData * sizeof(WCHAR); + if (count) datalen = *count; + if (!data && count) *count = 0; - if (lpData) + RtlInitAnsiString( &nameA, name ); + if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) { - lpValueBuffer = RtlAllocateHeap(ProcessHeap, - 0, - Length + sizeof(WCHAR)); - if (!lpValueBuffer) - { - return ERROR_OUTOFMEMORY; - } + return RtlNtStatusToDosError(status); + ClosePredefKey(hkey); } - else - { - lpValueBuffer = NULL; - if (lpcbData) - *lpcbData = 0; - } + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buffer, sizeof(buffer), &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; - if(!RtlCreateUnicodeStringFromAsciiz(&ValueName, - (LPSTR)lpValueName)) + /* we need to fetch the contents for a string type even if not requested, + * because we need to compute the length of the ASCII string. */ + if (data || is_string(info->Type)) { - ERR("RtlCreateUnicodeStringFromAsciiz failed!\n"); - ErrorCode = ERROR_OUTOFMEMORY; - goto cleanup; - } - - ErrorCode = RegQueryValueExW(hKey, - ValueName.Buffer, - lpReserved, - &Type, - (LPBYTE)lpValueBuffer, - &Length); - TRACE("ErrorCode %lu\n", ErrorCode); - - RtlFreeUnicodeString(&ValueName); + /* 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; + goto done; + } + info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr; + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buf_ptr, total_size, &total_size ); + } - if (ErrorCode == ERROR_SUCCESS || - ErrorCode == ERROR_MORE_DATA) - { + if (status) goto done; - if (is_string(Type)) + if (is_string(info->Type)) { - if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL) + DWORD len; + + RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size), + total_size - info_size ); + if (data && len) { - Status = RtlUnicodeToMultiByteN((PCHAR)lpData, *lpcbData, &Index, (PWCHAR)lpValueBuffer, Length); - if (NT_SUCCESS(Status)) - { - PCHAR szData = (PCHAR)lpData; - if(&szData[Index] < (PCHAR)(lpData + *lpcbData)) - { - szData[Index] = '\0'; - } - } + if (len > datalen) status = STATUS_BUFFER_OVERFLOW; else { - ErrorCode = RtlNtStatusToDosError(Status); + RtlUnicodeToMultiByteN( (char*)data, len, NULL, (WCHAR *)(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 (len < datalen && data[len-1]) data[len] = 0; } } - - Length = Length / sizeof(WCHAR); - } - else if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL) - { - if (*lpcbData < Length) - { - ErrorCode = ERROR_MORE_DATA; - } - else - { - RtlMoveMemory(lpData, lpValueBuffer, Length); - } + total_size = len + info_size; } - - if (lpcbData != NULL) + else if (data) { - *lpcbData = Length; + if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW; + else memcpy( data, buf_ptr + info_size, total_size - info_size ); } } + else status = STATUS_SUCCESS; - if (lpType != NULL) - { - *lpType = Type; - } - -cleanup: - if (lpValueBuffer != NULL) - { - RtlFreeHeap(ProcessHeap, 0, lpValueBuffer); - } + if (type) *type = info->Type; + if (count) *count = total_size - info_size; - return ErrorCode; + done: + if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr ); + RtlFreeUnicodeString( &nameW ); + ClosePredefKey(hkey); + return RtlNtStatusToDosError(status); } -- 2.17.1