windows-nt/Source/XPSP1/NT/sdktools/vmmreg32/regqmval.c
2020-09-26 16:20:57 +08:00

256 lines
7.7 KiB
C

//
// REGQMVAL.C
//
// Copyright (C) Microsoft Corporation, 1995
//
// Implementation of RegQueryMultipleValues and supporting functions.
//
#include "pch.h"
#ifdef VXD
#pragma VxD_RARE_CODE_SEG
#endif
#ifdef IS_32
//
// VMMRegQueryMultipleValues
//
// See Win32 documentation of RegQueryMultipleValues. However, the Win95
// implementation breaks many of the rules that are described in the
// documentation:
// * num_vals is a count of VALENT structures, not a size in bytes.
// * data is not DWORD aligned in lpValueBuffer.
// * if lpValueBuffer is too small, lpValueBuffer is not filled to the
// size specified by lpdwTotalSize.
//
// All of this plus dynamic keys makes this an extremely ugly routine, but
// every attempt was made to be compatible with the Win95 semantics.
//
LONG
REGAPI
VMMRegQueryMultipleValues(
HKEY hKey,
PVALENT val_list,
DWORD num_vals,
LPSTR lpValueBuffer,
LPDWORD lpdwTotalSize
)
{
int ErrorCode;
PVALENT pCurrentValent;
DWORD Counter;
DWORD BufferSize;
DWORD RequiredSize;
LPKEY_RECORD lpKeyRecord;
LPVALUE_RECORD lpValueRecord;
LPSTR lpCurrentBuffer;
#ifdef WANT_DYNKEY_SUPPORT
PVALCONTEXT pValueContext;
PINTERNAL_PROVIDER pProvider;
PPVALUE pProviderValue;
#endif
if (IsBadHugeReadPtr(val_list, sizeof(VALENT) * num_vals))
return ERROR_INVALID_PARAMETER;
if (IsBadHugeWritePtr(lpdwTotalSize, sizeof(DWORD)))
return ERROR_INVALID_PARAMETER;
if (IsBadHugeWritePtr(lpValueBuffer, *lpdwTotalSize))
return ERROR_INVALID_PARAMETER;
for (Counter = num_vals, pCurrentValent = val_list; Counter > 0; Counter--,
pCurrentValent++) {
if (IsBadStringPtr(pCurrentValent-> ve_valuename, (UINT) -1))
return ERROR_INVALID_PARAMETER;
}
if (!RgLockRegistry())
return ERROR_LOCK_FAILED;
if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) != ERROR_SUCCESS)
goto ReturnErrorCode;
#ifdef WANT_DYNKEY_SUPPORT
// Check if this a dynamic key that has a "get all" atomic callback. If
// the dynamic key just has "get one" callback, then we'll fall into the
// non-dynamic case.
if ((hKey-> PredefinedKeyIndex == INDEX_DYN_DATA) && !IsNullPtr(hKey->
pProvider-> ipi_R0_allvals)) {
pProvider = hKey-> pProvider;
pValueContext = RgSmAllocMemory(sizeof(struct val_context) * num_vals);
if (IsNullPtr(pValueContext)) {
ErrorCode = ERROR_OUTOFMEMORY;
goto ReturnErrorCode;
}
//
// Compute the required buffer size to hold all the value data and
// check it against the provided buffer size.
//
RequiredSize = 0;
for (Counter = 0, pCurrentValent = val_list; Counter < num_vals;
Counter++, pCurrentValent++) {
if ((ErrorCode = RgLookupValueByName(hKey, pCurrentValent->
ve_valuename, &lpKeyRecord, &lpValueRecord)) != ERROR_SUCCESS)
goto ReturnErrorCode;
// The value data contains only part of a PROVIDER structure.
pProviderValue = CONTAINING_RECORD(&lpValueRecord-> Name +
lpValueRecord-> NameLength, PVALUE, pv_valuelen);
pValueContext[Counter].value_context = pProviderValue->
pv_value_context;
pCurrentValent-> ve_type = pProviderValue-> pv_type;
if (hKey-> Flags & KEYF_PROVIDERHASVALUELENGTH) {
// Must zero it so that some providers don't try to stomp on
// lpData.
pCurrentValent-> ve_valuelen = 0;
ErrorCode = pProvider-> ipi_R0_1val(pProvider-> ipi_key_context,
&pValueContext[Counter], 1, NULL, &(pCurrentValent->
ve_valuelen), 0);
// Providers should really be returning either of these errors
// to us.
ASSERT((ErrorCode == ERROR_SUCCESS) || (ErrorCode ==
ERROR_MORE_DATA));
}
else {
pCurrentValent-> ve_valuelen = pProviderValue-> pv_valuelen;
}
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, FALSE);
pCurrentValent-> ve_valueptr = (DWORD) NULL;
RequiredSize += pCurrentValent-> ve_valuelen;
}
BufferSize = *lpdwTotalSize;
*lpdwTotalSize = RequiredSize;
if (BufferSize < RequiredSize)
ErrorCode = ERROR_MORE_DATA;
else if (pProvider-> ipi_R0_allvals(pProvider-> ipi_key_context,
pValueContext, num_vals, lpValueBuffer, lpdwTotalSize, 0) !=
ERROR_SUCCESS)
ErrorCode = ERROR_CANTREAD;
else {
ErrorCode = ERROR_SUCCESS;
// Copy the pointers to the value data back to the user's buffer.
// Don't ask me why, but the Win95 code copies the value length
// back again if the provider is maintaining it.
for (Counter = 0, pCurrentValent = val_list; Counter < num_vals;
Counter++, pCurrentValent++) {
pCurrentValent-> ve_valueptr = (DWORD)
pValueContext[Counter].val_buff_ptr;
if (hKey-> Flags & KEYF_PROVIDERHASVALUELENGTH)
pCurrentValent-> ve_valuelen = pValueContext[Counter].valuelen;
}
}
RgSmFreeMemory(pValueContext);
goto ReturnErrorCode;
}
#endif
//
// First pass over the value names checks for the existence of the value
// and its size. We check the total size against the provided buffer size
// and bail out if necessary.
//
RequiredSize = 0;
for (Counter = num_vals, pCurrentValent = val_list; Counter > 0; Counter--,
pCurrentValent++) {
if ((ErrorCode = RgLookupValueByName(hKey, pCurrentValent->
ve_valuename, &lpKeyRecord, &lpValueRecord)) != ERROR_SUCCESS)
goto ReturnErrorCode;
ErrorCode = RgCopyFromValueRecord(hKey, lpValueRecord, NULL, NULL,
&(pCurrentValent-> ve_type), NULL, &(pCurrentValent-> ve_valuelen));
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, FALSE);
if (ErrorCode != ERROR_SUCCESS)
goto ReturnErrorCode;
pCurrentValent-> ve_valueptr = (DWORD) NULL;
RequiredSize += pCurrentValent-> ve_valuelen;
}
BufferSize = *lpdwTotalSize;
*lpdwTotalSize = RequiredSize;
if (BufferSize < RequiredSize) {
ErrorCode = ERROR_MORE_DATA;
goto ReturnErrorCode;
}
//
// Second pass copies the value data back to the user's buffer now that we
// know the buffer is large enough to contain the data.
//
lpCurrentBuffer = lpValueBuffer;
for (Counter = num_vals, pCurrentValent = val_list; Counter > 0; Counter--,
pCurrentValent++) {
if ((ErrorCode = RgLookupValueByName(hKey, pCurrentValent->
ve_valuename, &lpKeyRecord, &lpValueRecord)) != ERROR_SUCCESS)
goto ReturnErrorReading;
ErrorCode = RgCopyFromValueRecord(hKey, lpValueRecord, NULL, NULL, NULL,
lpCurrentBuffer, &(pCurrentValent-> ve_valuelen));
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, FALSE);
if (ErrorCode != ERROR_SUCCESS) {
ReturnErrorReading:
TRAP(); // Registry is internally inconsistent?
ErrorCode = ERROR_CANTREAD;
goto ReturnErrorCode;
}
pCurrentValent-> ve_valueptr = (DWORD) lpCurrentBuffer;
lpCurrentBuffer += pCurrentValent-> ve_valuelen;
}
ErrorCode = ERROR_SUCCESS;
ReturnErrorCode:
RgUnlockRegistry();
return ErrorCode;
}
#endif