Author: jgardou Date: Wed Oct 1 22:51:44 2014 New Revision: 64445
URL: http://svn.reactos.org/svn/reactos?rev=64445&view=rev Log: [ADVAPI32] - Fix a stupid crash I introduced in RegQueryValueExA - Reimplement RegEnumKeyExA as wrapper around RegEnumKeyExW - Implement RegEnumKeyExW for HKCR subkeys - Fix a few potential handle leaks CORE-8582
Modified: trunk/reactos/dll/win32/advapi32/reg/hkcr.c trunk/reactos/dll/win32/advapi32/reg/reg.c trunk/reactos/dll/win32/advapi32/reg/reg.h
Modified: trunk/reactos/dll/win32/advapi32/reg/hkcr.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/reg/hkcr... ============================================================================== --- trunk/reactos/dll/win32/advapi32/reg/hkcr.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/advapi32/reg/hkcr.c [iso-8859-1] Wed Oct 1 22:51:44 2014 @@ -263,7 +263,7 @@ }
/* See if the subkey already exists in HKCU. */ - ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, 0, KEY_READ, &TestKey); + ErrorCode = RegOpenKeyExW(QueriedKey, lpSubKey, 0, 0, &TestKey); if (ErrorCode != ERROR_FILE_NOT_FOUND) { if (ErrorCode == ERROR_SUCCESS) @@ -585,3 +585,217 @@
return ErrorCode; } + +/* HKCR version of RegEnumKeyExW */ +LONG +WINAPI +EnumHKCRKey( + _In_ HKEY hKey, + _In_ DWORD dwIndex, + _Out_ LPWSTR lpName, + _Inout_ LPDWORD lpcbName, + _Reserved_ LPDWORD lpReserved, + _Out_opt_ LPWSTR lpClass, + _Inout_opt_ LPDWORD lpcbClass, + _Out_opt_ PFILETIME lpftLastWriteTime) +{ + HKEY PreferredKey, FallbackKey; + DWORD NumPreferredSubKeys; + DWORD MaxFallbackSubKeyLen; + DWORD FallbackIndex; + WCHAR* FallbackSubKeyName = NULL; + LONG ErrorCode; + + ASSERT(IsHKCRKey(hKey)); + + /* Remove the HKCR flag while we're working */ + hKey = (HKEY)(((ULONG_PTR)hKey) & ~0x2); + + /* Get the preferred key */ + ErrorCode = GetPreferredHKCRKey(hKey, &PreferredKey); + if (ErrorCode != ERROR_SUCCESS) + { + if (ErrorCode == ERROR_FILE_NOT_FOUND) + { + /* Only the HKLM key exists */ + return RegEnumKeyExW( + hKey, + dwIndex, + lpName, + lpcbName, + lpReserved, + lpClass, + lpcbClass, + lpftLastWriteTime); + } + return ErrorCode; + } + + /* Get the fallback key */ + ErrorCode = GetFallbackHKCRKey(hKey, &FallbackKey, FALSE); + if (ErrorCode != ERROR_SUCCESS) + { + if (PreferredKey != hKey) + RegCloseKey(PreferredKey); + if (ErrorCode == ERROR_FILE_NOT_FOUND) + { + /* Only the HKCU key exists */ + return RegEnumKeyExW( + hKey, + dwIndex, + lpName, + lpcbName, + lpReserved, + lpClass, + lpcbClass, + lpftLastWriteTime); + } + return ErrorCode; + } + + /* Get some info on the HKCU side */ + ErrorCode = RegQueryInfoKeyW( + PreferredKey, + NULL, + NULL, + NULL, + &NumPreferredSubKeys, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (ErrorCode != ERROR_SUCCESS) + goto Exit; + + if (dwIndex < NumPreferredSubKeys) + { + /* HKCU side takes precedence */ + ErrorCode = RegEnumKeyExW( + PreferredKey, + dwIndex, + lpName, + lpcbName, + lpReserved, + lpClass, + lpcbClass, + lpftLastWriteTime); + goto Exit; + } + + /* Here it gets tricky. We must enumerate the values from the HKLM side, + * without reporting those which are present on the HKCU side */ + + /* Squash out the indices from HKCU */ + dwIndex -= NumPreferredSubKeys; + + /* Get some info */ + ErrorCode = RegQueryInfoKeyW( + FallbackKey, + NULL, + NULL, + NULL, + NULL, + &MaxFallbackSubKeyLen, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (ErrorCode != ERROR_SUCCESS) + { + ERR("Could not query info of key %p (Err: %d)\n", FallbackKey, ErrorCode); + goto Exit; + } + + ERR("Maxfallbacksubkeylen: %d\n", MaxFallbackSubKeyLen); + + /* Allocate our buffer */ + FallbackSubKeyName = RtlAllocateHeap( + RtlGetProcessHeap(), 0, (MaxFallbackSubKeyLen + 1) * sizeof(WCHAR)); + if (!FallbackSubKeyName) + { + ErrorCode = ERROR_NOT_ENOUGH_MEMORY; + goto Exit; + } + + /* We must begin at the very first subkey of the fallback key, + * and then see if we meet keys that already are in the preferred key. + * In that case, we must bump dwIndex, as otherwise we would enumerate a key we already + * saw in a previous call. + */ + FallbackIndex = 0; + while (TRUE) + { + HKEY PreferredSubKey; + DWORD FallbackSubkeyLen = MaxFallbackSubKeyLen; + + /* Try enumerating */ + ErrorCode = RegEnumKeyExW( + FallbackKey, + FallbackIndex, + FallbackSubKeyName, + &FallbackSubkeyLen, + NULL, + NULL, + NULL, + NULL); + if (ErrorCode != ERROR_SUCCESS) + { + /* Most likely ERROR_NO_MORE_ITEMS */ + ERR("Returning %d.\n", ErrorCode); + goto Exit; + } + FallbackSubKeyName[FallbackSubkeyLen] = L'\0'; + + /* See if there is such a value on HKCU side */ + ErrorCode = RegOpenKeyExW( + PreferredKey, + FallbackSubKeyName, + 0, + 0, + &PreferredSubKey); + + if (ErrorCode == ERROR_SUCCESS) + { + RegCloseKey(PreferredSubKey); + /* So we already enumerated it on HKCU side. */ + dwIndex++; + } + else if (ErrorCode != ERROR_FILE_NOT_FOUND) + { + ERR("Got error %d while querying for %s on HKCU side.\n", ErrorCode, FallbackSubKeyName); + goto Exit; + } + + /* See if we caught up */ + if (FallbackIndex == dwIndex) + break; + + FallbackIndex++; + } + + /* We can finally enumerate on the fallback side */ + ErrorCode = RegEnumKeyExW( + FallbackKey, + dwIndex, + lpName, + lpcbName, + lpReserved, + lpClass, + lpcbClass, + lpftLastWriteTime); + +Exit: + if (PreferredKey != hKey) + RegCloseKey(PreferredKey); + if (FallbackKey != hKey) + RegCloseKey(FallbackKey); + if (FallbackSubKeyName) + RtlFreeHeap(RtlGetProcessHeap(), 0, FallbackSubKeyName); + + return ErrorCode; +}
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] Wed Oct 1 22:51:44 2014 @@ -1306,7 +1306,11 @@ }
if (IsHKCRKey(ParentKey)) - return DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved); + { + LONG ErrorCode = DeleteHKCRKey(ParentKey, lpSubKey, samDesired, Reserved); + ClosePredefKey(ParentKey); + return ErrorCode; + }
if (samDesired & KEY_WOW64_32KEY) ERR("Wow64 not yet supported!\n"); @@ -2442,166 +2446,81 @@ * * @implemented */ -LONG WINAPI -RegEnumKeyExA(HKEY hKey, - DWORD dwIndex, - LPSTR lpName, - LPDWORD lpcbName, - LPDWORD lpReserved, - LPSTR lpClass, - LPDWORD lpcbClass, - PFILETIME lpftLastWriteTime) -{ - union - { - KEY_NODE_INFORMATION Node; - KEY_BASIC_INFORMATION Basic; - } *KeyInfo; - - UNICODE_STRING StringU; - ANSI_STRING StringA; - LONG ErrorCode = ERROR_SUCCESS; - DWORD NameLength; - DWORD ClassLength = 0; - DWORD BufferSize; - ULONG ResultSize; - HANDLE KeyHandle; - NTSTATUS Status; - - TRACE("RegEnumKeyExA(hKey 0x%x, dwIndex %d, lpName 0x%x, *lpcbName %d, lpClass 0x%x, lpcbClass %d)\n", - hKey, dwIndex, lpName, *lpcbName, lpClass, lpcbClass ? *lpcbClass : 0); - - if ((lpClass) && (!lpcbClass)) - { - return ERROR_INVALID_PARAMETER; - } - - Status = MapDefaultKey(&KeyHandle, hKey); - if (!NT_SUCCESS(Status)) - { - return RtlNtStatusToDosError(Status); - } - +LONG +WINAPI +RegEnumKeyExA( + _In_ HKEY hKey, + _In_ DWORD dwIndex, + _Out_ LPSTR lpName, + _Inout_ LPDWORD lpcbName, + _Reserved_ LPDWORD lpReserved, + _Out_opt_ LPSTR lpClass, + _Inout_opt_ LPDWORD lpcbClass, + _Out_opt_ PFILETIME lpftLastWriteTime) +{ + WCHAR* NameBuffer = NULL; + WCHAR* ClassBuffer = NULL; + DWORD NameLength, ClassLength; + LONG ErrorCode; + + /* Allocate our buffers */ if (*lpcbName > 0) { - NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR); - } - else - { - NameLength = 0; + NameLength = *lpcbName; + NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbName * sizeof(WCHAR)); + if (NameBuffer == NULL) + { + ErrorCode = ERROR_NOT_ENOUGH_MEMORY; + goto Exit; + } }
if (lpClass) { if (*lpcbClass > 0) { - ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); - } - else - { - ClassLength = 0; - } - - /* The class name should start at a dword boundary */ - BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength; - } - else - { - BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength; - } - - KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize); - if (KeyInfo == NULL) - { - ErrorCode = ERROR_OUTOFMEMORY; - goto Cleanup; - } - - Status = NtEnumerateKey(KeyHandle, - (ULONG)dwIndex, - lpClass == NULL ? KeyBasicInformation : KeyNodeInformation, - KeyInfo, - BufferSize, - &ResultSize); - TRACE("NtEnumerateKey() returned status 0x%X\n", Status); - if (!NT_SUCCESS(Status)) - { - ErrorCode = RtlNtStatusToDosError (Status); - } - else - { - if (lpClass == NULL) - { - if (KeyInfo->Basic.NameLength > NameLength) + ClassLength = *lpcbClass; + ClassBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, *lpcbClass * sizeof(WCHAR)); + if (ClassBuffer == NULL) { - ErrorCode = ERROR_BUFFER_OVERFLOW; + ErrorCode = ERROR_NOT_ENOUGH_MEMORY; + goto Exit; } - else - { - StringU.Buffer = KeyInfo->Basic.Name; - StringU.Length = KeyInfo->Basic.NameLength; - StringU.MaximumLength = KeyInfo->Basic.NameLength; - } - } - else - { - if (KeyInfo->Node.NameLength > NameLength || - KeyInfo->Node.ClassLength > ClassLength) - { - ErrorCode = ERROR_BUFFER_OVERFLOW; - } - else - { - StringA.Buffer = lpClass; - StringA.Length = 0; - StringA.MaximumLength = *lpcbClass; - StringU.Buffer = (PWCHAR)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset); - StringU.Length = KeyInfo->Node.ClassLength; - StringU.MaximumLength = KeyInfo->Node.ClassLength; - RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE); - lpClass[StringA.Length] = 0; - *lpcbClass = StringA.Length; - StringU.Buffer = KeyInfo->Node.Name; - StringU.Length = KeyInfo->Node.NameLength; - StringU.MaximumLength = KeyInfo->Node.NameLength; - } - } - - if (ErrorCode == ERROR_SUCCESS) - { - StringA.Buffer = lpName; - StringA.Length = 0; - StringA.MaximumLength = *lpcbName; - RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE); - lpName[StringA.Length] = 0; - *lpcbName = StringA.Length; - if (lpftLastWriteTime != NULL) - { - if (lpClass == NULL) - { - lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart; - lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart; - } - else - { - lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart; - lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart; - } - } - } - } - - /*TRACE("Key Namea0 Length %d\n", StringU.Length);*/ /* BUGBUG could be uninitialized */ - TRACE("Key Name1 Length %d\n", NameLength); - TRACE("Key Name Length %d\n", *lpcbName); - TRACE("Key Name %s\n", lpName); - - RtlFreeHeap(ProcessHeap, - 0, - KeyInfo); - -Cleanup: - ClosePredefKey(KeyHandle); + } + } + + /* Do the actual call */ + ErrorCode = RegEnumKeyExW( + hKey, + dwIndex, + NameBuffer, + lpcbName, + lpReserved, + ClassBuffer, + lpcbClass, + lpftLastWriteTime); + + if (ErrorCode != ERROR_SUCCESS) + goto Exit; + + /* Convert the strings */ + RtlUnicodeToMultiByteN(lpName, *lpcbName, 0, NameBuffer, *lpcbName * sizeof(WCHAR)); + /* NULL terminate if we can */ + if (NameLength > *lpcbName) + lpName[*lpcbName] = '\0'; + + if (lpClass) + { + RtlUnicodeToMultiByteN(lpClass, *lpcbClass, 0, NameBuffer, *lpcbClass * sizeof(WCHAR)); + if (ClassLength > *lpcbClass) + lpClass[*lpcbClass] = '\0'; + } + +Exit: + if (NameBuffer) + RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); + if (ClassBuffer) + RtlFreeHeap(RtlGetProcessHeap(), 0, ClassBuffer);
return ErrorCode; } @@ -2612,15 +2531,17 @@ * * @implemented */ -LONG WINAPI -RegEnumKeyExW(HKEY hKey, - DWORD dwIndex, - LPWSTR lpName, - LPDWORD lpcbName, - LPDWORD lpReserved, - LPWSTR lpClass, - LPDWORD lpcbClass, - PFILETIME lpftLastWriteTime) +LONG +WINAPI +RegEnumKeyExW( + _In_ HKEY hKey, + _In_ DWORD dwIndex, + _Out_ LPWSTR lpName, + _Inout_ LPDWORD lpcbName, + _Reserved_ LPDWORD lpReserved, + _Out_opt_ LPWSTR lpClass, + _Inout_opt_ LPDWORD lpcbClass, + _Out_opt_ PFILETIME lpftLastWriteTime) { union { @@ -2641,6 +2562,21 @@ if (!NT_SUCCESS(Status)) { return RtlNtStatusToDosError(Status); + } + + if (IsHKCRKey(KeyHandle)) + { + ErrorCode = EnumHKCRKey( + KeyHandle, + dwIndex, + lpName, + lpcbName, + lpReserved, + lpClass, + lpcbClass, + lpftLastWriteTime); + ClosePredefKey(KeyHandle); + return ErrorCode; }
if (*lpcbName > 0) @@ -3419,7 +3355,11 @@ }
if (IsHKCRKey(KeyHandle)) - return OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult); + { + ErrorCode = OpenHKCRKey(KeyHandle, lpSubKey, ulOptions, samDesired, phkResult); + ClosePredefKey(KeyHandle); + return ErrorCode; + }
if (ulOptions & REG_OPTION_OPEN_LINK) Attributes |= OBJ_OPENLINK; @@ -4035,7 +3975,7 @@ ErrorCode = RegQueryValueExW(hkeyorg, nameW.Buffer, NULL, &LocalType, NULL, &BufferSize); if (ErrorCode != ERROR_SUCCESS) { - if (!data) + if ((!data) && count) *count = 0; RtlFreeUnicodeString(&nameW); return ErrorCode;
Modified: trunk/reactos/dll/win32/advapi32/reg/reg.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/reg/reg.... ============================================================================== --- trunk/reactos/dll/win32/advapi32/reg/reg.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/advapi32/reg/reg.h [iso-8859-1] Wed Oct 1 22:51:44 2014 @@ -72,3 +72,15 @@ _In_ CONST BYTE* Data, _In_ DWORD DataSize);
+LONG +WINAPI +EnumHKCRKey( + _In_ HKEY hKey, + _In_ DWORD dwIndex, + _Out_ LPWSTR lpName, + _Inout_ LPDWORD lpcbName, + _Reserved_ LPDWORD lpReserved, + _Out_opt_ LPWSTR lpClass, + _Inout_opt_ LPDWORD lpcbClass, + _Out_opt_ PFILETIME lpftLastWriteTime); +