|
|
//
// REGQMVAL.C
//
// Copyright (C) Microsoft Corporation, 1995-1996
//
// 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 (IsDynDataKey(hKey) && !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-> BigKeyLockedBlockIndex, 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-> BigKeyLockedBlockIndex, 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-> BigKeyLockedBlockIndex, 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
|