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

@ -850,166 +850,163 @@ RegEnumKeyExA (HKEY hKey,
LPDWORD lpcbClass, LPDWORD lpcbClass,
PFILETIME lpftLastWriteTime) PFILETIME lpftLastWriteTime)
{ {
union 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;
DWORD ResultSize;
HANDLE KeyHandle;
NTSTATUS Status;
DPRINT("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))
{
SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
}
Status = MapDefaultKey(&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbName > 0)
{
NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
}
else
{
NameLength = 0;
}
if (lpClass)
{
if (*lpcbClass > 0)
{ {
ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR); KEY_NODE_INFORMATION Node;
} KEY_BASIC_INFORMATION Basic;
else } *KeyInfo;
UNICODE_STRING StringU;
ANSI_STRING StringA;
LONG ErrorCode = ERROR_SUCCESS;
DWORD NameLength;
DWORD ClassLength = 0;
DWORD BufferSize;
DWORD ResultSize;
HANDLE KeyHandle;
NTSTATUS Status;
DPRINT("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))
{ {
ClassLength = 0; SetLastError (ERROR_INVALID_PARAMETER);
return ERROR_INVALID_PARAMETER;
} }
/* The class name should start at a dword boundary */ Status = MapDefaultKey(&KeyHandle, hKey);
BufferSize = ((sizeof(KEY_NODE_INFORMATION) + NameLength + 3) & ~3) + ClassLength; if (!NT_SUCCESS(Status))
}
else
{
BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;
}
KeyInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (KeyInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateKey (KeyHandle,
(ULONG)dwIndex,
lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
KeyInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpClass == NULL)
{ {
if (KeyInfo->Basic.NameLength > NameLength) ErrorCode = RtlNtStatusToDosError (Status);
{ SetLastError (ErrorCode);
ErrorCode = ERROR_BUFFER_OVERFLOW; return ErrorCode;
}
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) if (*lpcbName > 0)
{ {
StringA.Buffer = lpName; NameLength = min (*lpcbName - 1 , REG_MAX_NAME_SIZE) * sizeof (WCHAR);
StringA.Length = 0; }
StringA.MaximumLength = *lpcbName; else
RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE); {
lpName[StringA.Length] = 0; NameLength = 0;
*lpcbName = StringA.Length; }
if (lpftLastWriteTime != NULL)
{ if (lpClass)
if (lpClass == NULL) {
if (*lpcbClass > 0)
{ {
lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart; ClassLength = min (*lpcbClass -1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;
} }
else else
{ {
lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart; ClassLength = 0;
lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;
} }
}
/* 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;
} }
}
DPRINT("Key Namea0 Length %d\n", StringU.Length); KeyInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
DPRINT("Key Namea1 Length %d\n", NameLength); if (KeyInfo == NULL)
DPRINT("Key Namea Length %d\n", *lpcbName); {
DPRINT("Key Namea %s\n", lpName); SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
RtlFreeHeap (ProcessHeap, Status = NtEnumerateKey (KeyHandle,
0, (ULONG)dwIndex,
KeyInfo); lpClass == NULL ? KeyBasicInformation : KeyNodeInformation,
KeyInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpClass == NULL)
{
if (KeyInfo->Basic.NameLength > NameLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
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) if (ErrorCode == ERROR_SUCCESS)
{ {
SetLastError(ErrorCode); 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;
}
}
}
}
return ErrorCode; DPRINT("Key Namea0 Length %d\n", StringU.Length);
DPRINT("Key Namea1 Length %d\n", NameLength);
DPRINT("Key Namea Length %d\n", *lpcbName);
DPRINT("Key Namea %s\n", lpName);
RtlFreeHeap (ProcessHeap,
0,
KeyInfo);
if (ErrorCode != ERROR_SUCCESS)
{
SetLastError(ErrorCode);
}
return ErrorCode;
} }
@ -1174,161 +1171,222 @@ 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
{
KEY_VALUE_FULL_INFORMATION Full;
KEY_VALUE_BASIC_INFORMATION Basic;
} *ValueInfo;
ULONG NameLength;
ULONG BufferSize;
ULONG DataLength = 0;
ULONG ResultSize;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
UNICODE_STRING StringU;
ANSI_STRING StringA;
BOOL IsStringType;
ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbValueName > 0)
{
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
NameLength = 0;
}
if (lpData)
{
DataLength = min (*lpcbData * sizeof(WCHAR), REG_MAX_DATA_SIZE);
BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
}
else
{
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
}
ValueInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (ValueInfo == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpData)
{
IsStringType = (ValueInfo->Full.Type == REG_SZ) ||
(ValueInfo->Full.Type == REG_MULTI_SZ) ||
(ValueInfo->Full.Type == REG_EXPAND_SZ);
if (ValueInfo->Full.NameLength > NameLength ||
(!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
ValueInfo->Full.DataLength > DataLength)
{
ErrorCode = ERROR_BUFFER_OVERFLOW;
}
else
{
if (IsStringType)
{
StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
StringU.Length = ValueInfo->Full.DataLength;
StringU.MaximumLength = DataLength;
StringA.Buffer = (PCHAR)lpData;
StringA.Length = 0;
StringA.MaximumLength = *lpcbData;
RtlUnicodeStringToAnsiString (&StringA,
&StringU,
FALSE);
*lpcbData = StringA.Length;
}
else
{
RtlCopyMemory (lpData,
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
ValueInfo->Full.DataLength);
*lpcbData = ValueInfo->Full.DataLength;
}
StringU.Buffer = ValueInfo->Full.Name;
StringU.Length = ValueInfo->Full.NameLength;
StringU.MaximumLength = NameLength;
}
}
else
{ {
if (ValueInfo->Basic.NameLength > NameLength) KEY_VALUE_FULL_INFORMATION Full;
{ KEY_VALUE_BASIC_INFORMATION Basic;
ErrorCode = ERROR_BUFFER_OVERFLOW; } *ValueInfo;
}
else ULONG NameLength;
{ ULONG BufferSize;
StringU.Buffer = ValueInfo->Basic.Name; ULONG DataLength = 0;
StringU.Length = ValueInfo->Basic.NameLength; ULONG ResultSize;
StringU.MaximumLength = NameLength; HANDLE KeyHandle;
} LONG ErrorCode;
NTSTATUS Status;
UNICODE_STRING StringU;
ANSI_STRING StringA;
BOOL IsStringType;
ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle, hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
} }
if (ErrorCode == ERROR_SUCCESS) if (*lpcbValueName > 0)
{ NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
StringA.Buffer = (PCHAR)lpValueName; else
StringA.Length = 0; NameLength = 0;
StringA.MaximumLength = *lpcbValueName;
RtlUnicodeStringToAnsiString (&StringA, if (lpData)
&StringU, {
FALSE); DataLength = min (*lpcbData * sizeof(WCHAR), REG_MAX_DATA_SIZE);
StringA.Buffer[StringA.Length] = 0; BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
*lpcbValueName = StringA.Length; }
if (lpType) else
{ {
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type; BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
}
} }
}
RtlFreeHeap (ProcessHeap, ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
0, if (ValueInfo == NULL)
ValueInfo); {
if (ErrorCode != ERROR_SUCCESS) SetLastError(ERROR_OUTOFMEMORY);
{ return ERROR_OUTOFMEMORY;
SetLastError(ErrorCode); }
}
return ErrorCode; Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(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
{
if (lpData)
{
IsStringType = (ValueInfo->Full.Type == REG_SZ) ||
(ValueInfo->Full.Type == REG_MULTI_SZ) ||
(ValueInfo->Full.Type == REG_EXPAND_SZ);
if (ValueInfo->Full.NameLength > NameLength ||
(!IsStringType && ValueInfo->Full.DataLength > *lpcbData) ||
ValueInfo->Full.DataLength > DataLength)
{
// 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
{
if (IsStringType)
{
StringU.Buffer = (PWCHAR)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset);
StringU.Length = ValueInfo->Full.DataLength;
StringU.MaximumLength = DataLength;
StringA.Buffer = (PCHAR)lpData;
StringA.Length = 0;
StringA.MaximumLength = *lpcbData;
RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
*lpcbData = StringA.Length;
}
else
{
RtlCopyMemory (lpData,
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
ValueInfo->Full.DataLength);
*lpcbData = ValueInfo->Full.DataLength;
}
StringU.Buffer = ValueInfo->Full.Name;
StringU.Length = ValueInfo->Full.NameLength;
StringU.MaximumLength = NameLength;
}
}
else
{
if (ValueInfo->Basic.NameLength > NameLength)
{
// 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
{
StringU.Buffer = ValueInfo->Basic.Name;
StringU.Length = ValueInfo->Basic.NameLength;
StringU.MaximumLength = NameLength;
}
}
if (ErrorCode == ERROR_SUCCESS)
{
StringA.Buffer = (PCHAR)lpValueName;
StringA.Length = 0;
StringA.MaximumLength = *lpcbValueName;
RtlUnicodeStringToAnsiString (&StringA, &StringU, FALSE);
StringA.Buffer[StringA.Length] = 0;
*lpcbValueName = StringA.Length;
if (lpType)
{
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
}
}
}
RtlFreeHeap (ProcessHeap, 0, ValueInfo);
if (ErrorCode != ERROR_SUCCESS)
SetLastError(ErrorCode);
return ErrorCode;
} }
@ -1347,127 +1405,170 @@ RegEnumValueW (HKEY hKey,
LPBYTE lpData, LPBYTE lpData,
LPDWORD lpcbData) LPDWORD lpcbData)
{ {
union union
{
KEY_VALUE_FULL_INFORMATION Full;
KEY_VALUE_BASIC_INFORMATION Basic;
} *ValueInfo;
ULONG NameLength;
ULONG BufferSize;
ULONG DataLength = 0;
ULONG ResultSize;
HANDLE KeyHandle;
LONG ErrorCode;
NTSTATUS Status;
ErrorCode = ERROR_SUCCESS;
Status = MapDefaultKey (&KeyHandle,
hKey);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
SetLastError (ErrorCode);
return ErrorCode;
}
if (*lpcbValueName > 0)
{
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
}
else
{
NameLength = 0;
}
if (lpData)
{
DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
}
else
{
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
}
ValueInfo = RtlAllocateHeap (ProcessHeap,
0,
BufferSize);
if (ValueInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
if (!NT_SUCCESS(Status))
{
ErrorCode = RtlNtStatusToDosError (Status);
}
else
{
if (lpData)
{ {
if (ValueInfo->Full.DataLength > DataLength || KEY_VALUE_FULL_INFORMATION Full;
ValueInfo->Full.NameLength > NameLength) KEY_VALUE_BASIC_INFORMATION Basic;
{ } *ValueInfo;
ErrorCode = ERROR_BUFFER_OVERFLOW;
} ULONG NameLength;
else ULONG BufferSize;
{ ULONG DataLength = 0;
RtlCopyMemory (lpValueName, ULONG ResultSize;
ValueInfo->Full.Name, HANDLE KeyHandle;
ValueInfo->Full.NameLength); LONG ErrorCode;
*lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR)); NTSTATUS Status;
lpValueName[*lpcbValueName] = 0;
RtlCopyMemory (lpData, ErrorCode = ERROR_SUCCESS;
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
ValueInfo->Full.DataLength); Status = MapDefaultKey (&KeyHandle, hKey);
*lpcbData = (DWORD)ValueInfo->Full.DataLength; if (!NT_SUCCESS(Status))
}
}
else
{ {
if (ValueInfo->Basic.NameLength > NameLength) ErrorCode = RtlNtStatusToDosError (Status);
{ SetLastError (ErrorCode);
ErrorCode = ERROR_BUFFER_OVERFLOW; return ErrorCode;
}
else
{
RtlCopyMemory (lpValueName,
ValueInfo->Basic.Name,
ValueInfo->Basic.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0;
}
if (NULL != lpcbData)
{
*lpcbData = (DWORD)ValueInfo->Full.DataLength;
}
} }
if (ErrorCode == ERROR_SUCCESS && lpType != NULL) if (*lpcbValueName > 0)
NameLength = min (*lpcbValueName - 1, REG_MAX_NAME_SIZE) * sizeof(WCHAR);
else
NameLength = 0;
if (lpData)
{ {
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type; DataLength = min(*lpcbData, REG_MAX_DATA_SIZE);
BufferSize = ((sizeof(KEY_VALUE_FULL_INFORMATION) + NameLength + 3) & ~3) + DataLength;
} }
} else
{
BufferSize = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameLength;
}
ValueInfo = RtlAllocateHeap (ProcessHeap, 0, BufferSize);
if (ValueInfo == NULL)
{
SetLastError (ERROR_OUTOFMEMORY);
return ERROR_OUTOFMEMORY;
}
Status = NtEnumerateValueKey (KeyHandle,
(ULONG)dwIndex,
lpData ? KeyValueFullInformation : KeyValueBasicInformation,
ValueInfo,
BufferSize,
&ResultSize);
RtlFreeHeap (ProcessHeap, DPRINT("NtEnumerateValueKey() returned status 0x%X\n", Status);
0, if (!NT_SUCCESS(Status))
ValueInfo); {
ErrorCode = RtlNtStatusToDosError (Status);
if (ErrorCode != ERROR_SUCCESS) // handle case when BufferSize was too small
{ // we must let caller know the minimum accepted size
SetLastError (ErrorCode); // and value type
} if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
{
ErrorCode = ERROR_MORE_DATA;
return ErrorCode; // 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
{
if (lpData)
{
if (ValueInfo->Full.DataLength > DataLength ||
ValueInfo->Full.NameLength > NameLength)
{
// 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
{
RtlCopyMemory (lpValueName, ValueInfo->Full.Name, ValueInfo->Full.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Full.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0;
RtlCopyMemory (lpData,
(PVOID)((ULONG_PTR)ValueInfo + ValueInfo->Full.DataOffset),
ValueInfo->Full.DataLength);
*lpcbData = (DWORD)ValueInfo->Full.DataLength;
}
}
else
{
if (ValueInfo->Basic.NameLength > NameLength)
{
// overflow name
ErrorCode = ERROR_MORE_DATA;
if (lpcbData)
*lpcbData = ValueInfo->Full.DataLength;
if (lpType)
*lpType = ValueInfo->Basic.Type;
}
else
{
RtlCopyMemory (lpValueName, ValueInfo->Basic.Name, ValueInfo->Basic.NameLength);
*lpcbValueName = (DWORD)(ValueInfo->Basic.NameLength / sizeof(WCHAR));
lpValueName[*lpcbValueName] = 0;
}
if (NULL != lpcbData)
{
*lpcbData = (DWORD)ValueInfo->Full.DataLength;
DPRINT1("BUG: Using ValueInfo as FULL when it is really BASIC\n");
}
}
if (ErrorCode == ERROR_SUCCESS && lpType != NULL)
{
*lpType = lpData ? ValueInfo->Full.Type : ValueInfo->Basic.Type;
}
}
RtlFreeHeap (ProcessHeap, 0, ValueInfo);
if (ErrorCode != ERROR_SUCCESS)
SetLastError (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,