Fixed RegEnumValueA/W behaviour when output buffers are too small. This fixes 20+ tests from "advapi32_test registry" (now it has only 2 failures - but that's a reduced tests set!).

I beg my pardon for reformatting these two funcs and fixing bugs in one commit, I will do it in different commits in the future.

svn path=/trunk/; revision=14891
This commit is contained in:
Aleksey Bragin 2005-04-30 21:11:34 +00:00
parent acb9e6951d
commit be9f61a8b9

View file

@ -875,8 +875,7 @@ RegEnumKeyExA (HKEY hKey,
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
} }
Status = MapDefaultKey(&KeyHandle, Status = MapDefaultKey(&KeyHandle, hKey);
hKey);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
@ -912,9 +911,7 @@ RegEnumKeyExA (HKEY hKey,
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength; BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
} }
KeyInfo = RtlAllocateHeap (ProcessHeap, KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
0,
BufferSize);
if (KeyInfo == NULL) if (KeyInfo == NULL)
{ {
SetLastError (ERROR_OUTOFMEMORY); SetLastError (ERROR_OUTOFMEMORY);
@ -1174,11 +1171,11 @@ LONG STDCALL
RegEnumValueA (HKEY hKey, RegEnumValueA (HKEY hKey,
DWORD dwIndex, DWORD dwIndex,
LPSTR lpValueName, LPSTR lpValueName,
LPDWORD lpcbValueName, LPDWORD lpcbValueName, // lpValueName buffer len
LPDWORD lpReserved, LPDWORD lpReserved,
LPDWORD lpType, LPDWORD lpType,
LPBYTE lpData, LPBYTE lpData,
LPDWORD lpcbData) LPDWORD lpcbData) // lpData buffer len
{ {
union union
{ {
@ -1199,8 +1196,7 @@ RegEnumValueA (HKEY hKey,
ErrorCode = ERROR_SUCCESS; ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle, Status = MapDefaultKey (&KeyHandle, hKey);
hKey);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
@ -1209,13 +1205,9 @@ RegEnumValueA (HKEY hKey,
} }
if (*lpcbValueName > 0) if (*lpcbValueName > 0)
{
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else else
{
NameLength = 0; NameLength = 0;
}
if (lpData) if (lpData)
{ {
@ -1227,9 +1219,7 @@ RegEnumValueA (HKEY hKey,
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength; BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
} }
ValueInfo = RtlAllocateHeap (ProcessHeap, ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
0,
BufferSize);
if (ValueInfo == NULL) if (ValueInfo == NULL)
{ {
SetLastError(ERROR_OUTOFMEMORY); SetLastError(ERROR_OUTOFMEMORY);
@ -1247,6 +1237,59 @@ RegEnumValueA (HKEY hKey,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
// handle case when BufferSize was too small
// we must let caller know the minimum accepted size
// and value type
if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
{
ErrorCode = ERROR_MORE_DATA;
// query now with the sufficient buffer size
RtlFreeHeap (ProcessHeap, 0, ValueInfo);
BufferSize = ResultSize;
ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize); // will be freed at the bottom, as usual
if (ValueInfo == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
if (!NT_SUCCESS(Status))
{
// ok, some other error
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
// we have information now, pass it to the caller
// but don't touch valueName length here
IsStringType = (ValueInfo->Full.Type == REG_SZ) ||
(ValueInfo->Full.Type == REG_MULTI_SZ) ||
(ValueInfo->Full.Type == REG_EXPAND_SZ); //FIXME: Include REG_LINK ?
if (lpData)
{
if (lpcbData)
{
if (IsStringType)
*lpcbData = ValueInfo->Full.DataLength / sizeof(WCHAR);
else
*lpcbData = ValueInfo->Full.DataLength;
}
}
// pass type also
if (lpType)
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
}
}
} }
else else
{ {
@ -1259,7 +1302,20 @@ RegEnumValueA (HKEY hKey,
(!IsStringType && ValueInfo->Full.DataLength > *lpcbData) || (!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
ValueInfo->Full.DataLength > DataLength) ValueInfo->Full.DataLength > DataLength)
{ {
ErrorCode = ERROR_BUFFER_OVERFLOW; // overflow data
ErrorCode = ERROR_MORE_DATA;
// return correct information for data length and type
if (lpcbData)
{
if (IsStringType)
*lpcbData = ValueInfo->Full.DataLength / sizeof(WCHAR);
else
*lpcbData = ValueInfo->Full.DataLength;
}
if (lpType)
*lpType = ValueInfo->Full.Type;
} }
else else
{ {
@ -1271,9 +1327,7 @@ RegEnumValueA (HKEY hKey,
StringA.Buffer = (PCHAR)lpData; StringA.Buffer = (PCHAR)lpData;
StringA.Length = 0; StringA.Length = 0;
StringA.MaximumLength = *lpcbData; StringA.MaximumLength = *lpcbData;
RtlUnicodeStringToAnsiString (&StringA, RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
&StringU,
FALSE);
*lpcbData = StringA.Length; *lpcbData = StringA.Length;
} }
else else
@ -1293,7 +1347,16 @@ RegEnumValueA (HKEY hKey,
{ {
if (ValueInfo->Basic.NameLength > NameLength) if (ValueInfo->Basic.NameLength > NameLength)
{ {
ErrorCode = ERROR_BUFFER_OVERFLOW; // overflow name
ErrorCode = ERROR_MORE_DATA;
if (IsStringType)
*lpcbData = ValueInfo->Full.DataLength / sizeof(WCHAR);
else
*lpcbData = ValueInfo->Full.DataLength;
if (lpType)
*lpType = ValueInfo->Basic.Type;
} }
else else
{ {
@ -1308,9 +1371,7 @@ RegEnumValueA (HKEY hKey,
StringA.Buffer = (PCHAR)lpValueName; StringA.Buffer = (PCHAR)lpValueName;
StringA.Length = 0; StringA.Length = 0;
StringA.MaximumLength = *lpcbValueName; StringA.MaximumLength = *lpcbValueName;
RtlUnicodeStringToAnsiString (&StringA, RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
&StringU,
FALSE);
StringA.Buffer[StringA.Length] = 0; StringA.Buffer[StringA.Length] = 0;
*lpcbValueName = StringA.Length; *lpcbValueName = StringA.Length;
if (lpType) if (lpType)
@ -1320,13 +1381,10 @@ RegEnumValueA (HKEY hKey,
} }
} }
RtlFreeHeap (ProcessHeap, RtlFreeHeap (ProcessHeap, 0, ValueInfo);
0,
ValueInfo);
if (ErrorCode != ERROR_SUCCESS) if (ErrorCode != ERROR_SUCCESS)
{
SetLastError(ErrorCode); SetLastError(ErrorCode);
}
return ErrorCode; return ErrorCode;
} }
@ -1363,8 +1421,7 @@ RegEnumValueW (HKEY hKey,
ErrorCode = ERROR_SUCCESS; ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle, Status = MapDefaultKey (&KeyHandle, hKey);
hKey);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
@ -1373,13 +1430,9 @@ RegEnumValueW (HKEY hKey,
} }
if (*lpcbValueName > 0) if (*lpcbValueName > 0)
{
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else else
{
NameLength = 0; NameLength = 0;
}
if (lpData) if (lpData)
{ {
@ -1390,9 +1443,7 @@ RegEnumValueW (HKEY hKey,
{ {
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength; BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
} }
ValueInfo = RtlAllocateHeap (ProcessHeap, ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
0,
BufferSize);
if (ValueInfo == NULL) if (ValueInfo == NULL)
{ {
SetLastError (ERROR_OUTOFMEMORY); SetLastError (ERROR_OUTOFMEMORY);
@ -1409,6 +1460,47 @@ RegEnumValueW (HKEY hKey,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
// handle case when BufferSize was too small
// we must let caller know the minimum accepted size
// and value type
if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
{
ErrorCode = ERROR_MORE_DATA;
// query now with the sufficient buffer size
RtlFreeHeap (ProcessHeap, 0, ValueInfo);
BufferSize = ResultSize;
ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize); // will be freed at the bottom, as usual
if (ValueInfo == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
if (!NT_SUCCESS(Status))
{
// ok, some other error
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
// we have information now, pass it to the caller
// but don't touch valueName length here
if (lpData && lpcbData)
*lpcbData = ValueInfo->Full.DataLength;
// pass type also
if (lpType)
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
}
}
} }
else else
{ {
@ -1417,13 +1509,19 @@ RegEnumValueW (HKEY hKey,
if (ValueInfo->Full.DataLength > DataLength || if (ValueInfo->Full.DataLength > DataLength ||
ValueInfo->Full.NameLength > NameLength) ValueInfo->Full.NameLength > NameLength)
{ {
ErrorCode = ERROR_BUFFER_OVERFLOW; // overflow data
ErrorCode = ERROR_MORE_DATA;
// return correct information for data length and type
if (lpcbData)
*lpcbData = ValueInfo->Full.DataLength;
if (lpType)
*lpType = ValueInfo->Full.Type;
} }
else else
{ {
RtlCopyMemory (lpValueName, RtlCopyMemory (lpValueName, ValueInfo->Full.Name, ValueInfo->Full.NameLength);
ValueInfo->Full.Name,
ValueInfo->Full.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR)); *lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0; lpValueName[*lpcbValueName] = 0;
RtlCopyMemory (lpData, RtlCopyMemory (lpData,
@ -1436,19 +1534,26 @@ RegEnumValueW (HKEY hKey,
{ {
if (ValueInfo->Basic.NameLength > NameLength) if (ValueInfo->Basic.NameLength > NameLength)
{ {
ErrorCode = ERROR_BUFFER_OVERFLOW; // overflow name
ErrorCode = ERROR_MORE_DATA;
if (lpcbData)
*lpcbData = ValueInfo->Full.DataLength;
if (lpType)
*lpType = ValueInfo->Basic.Type;
} }
else else
{ {
RtlCopyMemory (lpValueName, RtlCopyMemory (lpValueName, ValueInfo->Basic.Name, ValueInfo->Basic.NameLength);
ValueInfo->Basic.Name,
ValueInfo->Basic.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR)); *lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0; lpValueName[*lpcbValueName] = 0;
} }
if (NULL != lpcbData) if (NULL != lpcbData)
{ {
*lpcbData = (DWORD)ValueInfo->Full.DataLength; *lpcbData = (DWORD)ValueInfo->Full.DataLength;
DPRINT1("BUG: Using ValueInfo as FULL when it is really BASIC\n");
} }
} }
@ -1458,14 +1563,10 @@ RegEnumValueW (HKEY hKey,
} }
} }
RtlFreeHeap (ProcessHeap, RtlFreeHeap (ProcessHeap, 0, ValueInfo);
0,
ValueInfo);
if (ErrorCode != ERROR_SUCCESS) if (ErrorCode != ERROR_SUCCESS)
{
SetLastError (ErrorCode); SetLastError (ErrorCode);
}
return ErrorCode; return ErrorCode;
} }
@ -1741,7 +1842,7 @@ RegOpenKeyA (HKEY hKey,
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode); SetLastError (ErrorCode);
return ErrorCode; return Status;
} }
RtlCreateUnicodeStringFromAsciiz (&SubKeyString, RtlCreateUnicodeStringFromAsciiz (&SubKeyString,
@ -1796,7 +1897,7 @@ RegOpenKeyW (HKEY hKey,
{ {
ErrorCode = RtlNtStatusToDosError (Status); ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode); SetLastError (ErrorCode);
return ErrorCode; return Status;
} }
RtlInitUnicodeString (&SubKeyString, RtlInitUnicodeString (&SubKeyString,