Author: rharabien
Date: Sun Apr 10 21:24:49 2011
New Revision: 51314
URL:
http://svn.reactos.org/svn/reactos?rev=51314&view=rev
Log:
[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.
Modified:
trunk/reactos/dll/win32/advapi32/reg/reg.c
Modified: trunk/reactos/dll/win32/advapi32/reg/reg.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/reg/reg…
==============================================================================
--- trunk/reactos/dll/win32/advapi32/reg/reg.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/advapi32/reg/reg.c [iso-8859-1] Sun Apr 10 21:24:49 2011
@@ -3974,128 +3974,127 @@
}
-/************************************************************************
- * RegQueryValueExA
- *
- * @implemented
- */
-LONG WINAPI
-RegQueryValueExA(HKEY hKey,
- LPCSTR lpValueName,
- LPDWORD lpReserved,
- LPDWORD lpType,
- LPBYTE lpData,
- LPDWORD lpcbData)
-{
- UNICODE_STRING ValueName;
- LPWSTR lpValueBuffer;
- LONG ErrorCode;
- DWORD Length;
- DWORD Type;
- NTSTATUS Status;
- ULONG Index;
-
- TRACE("hKey 0x%X lpValueName %s lpData 0x%X lpcbData %d\n",
- hKey, lpValueName, lpData, lpcbData ? *lpcbData : 0);
-
- if (lpData != NULL && lpcbData == NULL)
- {
- return ERROR_INVALID_PARAMETER;
- }
-
- Length = (lpcbData == NULL || lpData == NULL) ? 0 : *lpcbData * sizeof(WCHAR);
-
- if (lpData)
- {
- lpValueBuffer = RtlAllocateHeap(ProcessHeap,
- 0,
- Length + sizeof(WCHAR));
- if (!lpValueBuffer)
- {
- return ERROR_OUTOFMEMORY;
- }
- }
- else
- {
- lpValueBuffer = NULL;
-
- if (lpcbData)
- *lpcbData = 0;
- }
-
- if(!RtlCreateUnicodeStringFromAsciiz(&ValueName,
- (LPSTR)lpValueName))
- {
- 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);
-
- if (ErrorCode == ERROR_SUCCESS ||
- ErrorCode == ERROR_MORE_DATA)
- {
-
- if (is_string(Type))
- {
- if (ErrorCode == ERROR_SUCCESS && lpValueBuffer != NULL)
+/******************************************************************************
+ * RegQueryValueExA [ADVAPI32.@]
+ *
+ * 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 hkeyorg,
+ LPCSTR name,
+ LPDWORD reserved,
+ LPDWORD type,
+ LPBYTE data,
+ LPDWORD count)
+{
+ 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("(%p,%s,%p,%p,%p,%p=%d)\n",
+ hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 );
+
+ if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
+ status = MapDefaultKey(&hkey, hkeyorg);
+ if (!NT_SUCCESS(status))
+ {
+ return RtlNtStatusToDosError(status);
+ }
+
+ if (count) datalen = *count;
+ if (!data && count) *count = 0;
+
+ RtlInitAnsiString( &nameA, name );
+ if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
+ {
+ return RtlNtStatusToDosError(status);
+ ClosePredefKey(hkey);
+ }
+
+ status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
+ buffer, sizeof(buffer), &total_size );
+ if (status && status != STATUS_BUFFER_OVERFLOW) goto done;
+
+ /* 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))
+ {
+ /* 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 = 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';
- }
- }
+ 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 (status) goto done;
+
+ if (is_string(info->Type))
+ {
+ DWORD len;
+
+ RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info_size),
+ total_size - info_size );
+ if (data && len)
+ {
+ 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);
- }
- }
-
- if (lpcbData != NULL)
- {
- *lpcbData = Length;
- }
- }
-
- if (lpType != NULL)
- {
- *lpType = Type;
- }
-
-cleanup:
- if (lpValueBuffer != NULL)
- {
- RtlFreeHeap(ProcessHeap, 0, lpValueBuffer);
- }
-
- return ErrorCode;
+ total_size = len + info_size;
+ }
+ else if (data)
+ {
+ 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 (type) *type = info->Type;
+ if (count) *count = total_size - info_size;
+
+ done:
+ if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
+ RtlFreeUnicodeString( &nameW );
+ ClosePredefKey(hkey);
+ return RtlNtStatusToDosError(status);
}