// // REGQVAL.C // // Copyright (C) Microsoft Corporation, 1995 // // Implementation of RegQueryValue, RegQueryValueEx and supporting functions. // #include "pch.h" // // RgLookupValueByName // (BIGKEY aware) // // Searches for the value with the specified name and returns a pointer to its // KEY_RECORD and VALUE_RECORD. // // This locks the datablock associated with the KEY_RECORD and VALUE_RECORD. // This is always hKey->BigKeyLockedBlockIndex // It is the callers responsibility to unlock the datablock. // int INTERNAL RgLookupValueByName( HKEY hKey, LPCSTR lpValueName, LPKEY_RECORD FAR* lplpKeyRecord, LPVALUE_RECORD FAR* lplpValueRecord ) { int ErrorCode; HKEY hKeyExtent; UINT Index; LPSTR ExtentKeyName; DWORD cbExtentKeyName; hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex; ErrorCode = RgLookupValueByNameStd(hKey, lpValueName, lplpKeyRecord, lplpValueRecord); // If this is a big key and we couldn't find it in the first key extent, then // try the remaining extents. if (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32 && (hKey->Flags & KEYF_BIGKEYROOT)) { if (IsNullPtr(ExtentKeyName = RgSmAllocMemory(MAXIMUM_SUB_KEY_LENGTH))) return ERROR_OUTOFMEMORY; Index = 0; do { cbExtentKeyName = MAXIMUM_SUB_KEY_LENGTH; if (RgLookupKeyByIndex(hKey, Index++, ExtentKeyName, &cbExtentKeyName, LK_BIGKEYEXT) != ERROR_SUCCESS) { ErrorCode = ERROR_CANTREAD16_FILENOTFOUND32; goto lFreeKeyName; } if (RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_OPEN | LK_BIGKEYEXT) != ERROR_SUCCESS) { ErrorCode = ERROR_CANTREAD16_FILENOTFOUND32; goto lFreeKeyName; } hKey-> BigKeyLockedBlockIndex = hKeyExtent-> BlockIndex; ErrorCode = RgLookupValueByNameStd(hKeyExtent, lpValueName, lplpKeyRecord, lplpValueRecord); RgDestroyKeyHandle(hKeyExtent); } while (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32); lFreeKeyName: RgSmFreeMemory(ExtentKeyName); } return ErrorCode; } // // RgLookupValueByNameStd // // Searches for the value with the specified name and returns a pointer to its // KEY_RECORD and VALUE_RECORD. // // This locks the datablock associated with the KEY_RECORD and VALUE_RECORD. // This is always hKey->BlockIndex. // It is the callers responsibility to unlock the datablock. // int INTERNAL RgLookupValueByNameStd( HKEY hKey, LPCSTR lpValueName, LPKEY_RECORD FAR* lplpKeyRecord, LPVALUE_RECORD FAR* lplpValueRecord ) { int ErrorCode; LPKEY_RECORD lpKeyRecord; UINT ValueNameLength; LPVALUE_RECORD lpValueRecord; UINT ValuesRemaining; // Handle Win95 registries that don't have a key record for the root key. if (IsNullBlockIndex(hKey-> BlockIndex)) return ERROR_CANTREAD16_FILENOTFOUND32; if ((ErrorCode = RgLockKeyRecord(hKey-> lpFileInfo, hKey-> BlockIndex, hKey-> KeyRecordIndex, &lpKeyRecord)) == ERROR_SUCCESS) { ValueNameLength = (IsNullPtr(lpValueName) ? 0 : (UINT) StrLen(lpValueName)); lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) &lpKeyRecord-> Name + lpKeyRecord-> NameLength + lpKeyRecord-> ClassLength); ValuesRemaining = lpKeyRecord-> ValueCount; // Should probably do more sanity checking on lpValueRecord while (ValuesRemaining) { if (lpValueRecord-> NameLength == ValueNameLength && (ValueNameLength == 0 || RgStrCmpNI(lpValueName, lpValueRecord-> Name, ValueNameLength) == 0)) { *lplpKeyRecord = lpKeyRecord; *lplpValueRecord = lpValueRecord; return ERROR_SUCCESS; } lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) &lpValueRecord-> Name + lpValueRecord-> NameLength + lpValueRecord-> DataLength); ValuesRemaining--; } RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, FALSE); ErrorCode = ERROR_CANTREAD16_FILENOTFOUND32; } return ErrorCode; } // // RgCopyFromValueRecord // // Shared routine for RegQueryValue and RegEnumValue. Copies the information // from the VALUE_RECORD to the user-provided buffers. All parameters should // have already been validated. // // Because all parameters have been validated, if lpData is valid, then // lpcbData MUST be valid. // int INTERNAL RgCopyFromValueRecord( HKEY hKey, LPVALUE_RECORD lpValueRecord, LPSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { int ErrorCode; UINT BytesToTransfer; #ifdef WANT_DYNKEY_SUPPORT PINTERNAL_PROVIDER pProvider; PPVALUE pProviderValue; struct val_context ValueContext; #endif #ifdef WANT_DYNKEY_SUPPORT if (IsDynDataKey(hKey)) { pProvider = hKey-> pProvider; if (IsNullPtr(pProvider)) return ERROR_CANTOPEN; // The value data contains only part of a PROVIDER structure. pProviderValue = CONTAINING_RECORD(&lpValueRecord-> Name + lpValueRecord-> NameLength, PVALUE, pv_valuelen); if (!IsNullPtr(lpType)) *lpType = pProviderValue-> pv_type; if (!(hKey-> Flags & KEYF_PROVIDERHASVALUELENGTH)) { BytesToTransfer = pProviderValue-> pv_valuelen; if (IsNullPtr(lpData)) goto ValueDataNotNeeded; if (BytesToTransfer > *lpcbData) { *lpcbData = BytesToTransfer; return ERROR_MORE_DATA; } // Win95 compatibility: now that we know the required number of // bytes, validate the data buffer. if (IsBadHugeWritePtr(lpData, BytesToTransfer)) return ERROR_INVALID_PARAMETER; } ValueContext.value_context = pProviderValue-> pv_value_context; if (!IsNullPtr(lpcbData)) { // Zero *lpcbData, if we aren't actually copying any data back to // the user's buffer. This keeps some providers from stomping on // lpData. if (IsNullPtr(lpData)) *lpcbData = 0; if ((ErrorCode = (int) pProvider-> ipi_R0_1val(pProvider-> ipi_key_context, &ValueContext, 1, lpData, lpcbData, 0)) != ERROR_SUCCESS) { // Win95 compatibility: the old code ignored any errors if // lpData is NULL. The below ASSERT will verify that we aren't // dropping errors. if (!IsNullPtr(lpData)) return ErrorCode; ASSERT((ErrorCode == ERROR_SUCCESS) || (ErrorCode == ERROR_MORE_DATA)); } } goto CopyValueName; } #endif if (!IsNullPtr(lpType)) *lpType = lpValueRecord-> DataType; BytesToTransfer = lpValueRecord-> DataLength; // The terminating null is not stored in the value record. if (lpValueRecord-> DataType == REG_SZ) BytesToTransfer++; // // Win32 compatibilty: lpData must be filled in before lpValueName. Word // NT and Excel NT broke when we validated lpValueName and failed the call // before filling in lpData which was valid. Don't rearrange this code! // if (!IsNullPtr(lpData)) { ErrorCode = ERROR_SUCCESS; if (BytesToTransfer > *lpcbData) { *lpcbData = BytesToTransfer; return ERROR_MORE_DATA; } // Win95 compatibility: now that we know the required number of bytes, // validate the data buffer. else if (IsBadHugeWritePtr(lpData, BytesToTransfer)) return ERROR_INVALID_PARAMETER; else { MoveMemory(lpData, &lpValueRecord-> Name + lpValueRecord-> NameLength, lpValueRecord-> DataLength); if (lpValueRecord-> DataType == REG_SZ) lpData[lpValueRecord-> DataLength] = '\0'; } } #ifdef WANT_DYNKEY_SUPPORT ValueDataNotNeeded: #endif if (!IsNullPtr(lpcbData)) *lpcbData = BytesToTransfer; #ifdef WANT_DYNKEY_SUPPORT CopyValueName: #endif if (!IsNullPtr(lpValueName)) { ErrorCode = ERROR_SUCCESS; if (*lpcbValueName <= lpValueRecord-> NameLength) { // Although we will not touch the lpData buffer if it's too small // to hold the value data, we will partially fill lpValueName if // it's too small. ErrorCode = ERROR_MORE_DATA; if (*lpcbValueName == 0) return ErrorCode; BytesToTransfer = (UINT) *lpcbValueName - 1; } else BytesToTransfer = lpValueRecord-> NameLength; MoveMemory(lpValueName, &lpValueRecord-> Name, BytesToTransfer); lpValueName[BytesToTransfer] = '\0'; // Does not include terminating null. *lpcbValueName = BytesToTransfer; return ErrorCode; } return ERROR_SUCCESS; } // // VMMRegQueryValueEx // // See Win32 documentation of RegQueryValueEx. // LONG REGAPI VMMRegQueryValueEx( HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ) { int ErrorCode; LPKEY_RECORD lpKeyRecord; LPVALUE_RECORD lpValueRecord; if (IsBadOptionalStringPtr(lpValueName, (UINT) -1)) return ERROR_INVALID_PARAMETER; if (IsBadHugeOptionalWritePtr(lpType, sizeof(DWORD))) return ERROR_INVALID_PARAMETER; if (!IsNullPtr(lpType)) *lpType = 0; // assume unknown data type if (IsNullPtr(lpcbData)) { if (!IsNullPtr(lpData)) return ERROR_INVALID_PARAMETER; } else { // Win95 compatibility: don't validate lpData is of size *lpcbData. // Instead of validating the entire buffer, we'll validate just the // required buffer length in RgCopyFromValueRecord. if (IsBadHugeWritePtr(lpcbData, sizeof(DWORD))) return ERROR_INVALID_PARAMETER; } if (!RgLockRegistry()) return ERROR_LOCK_FAILED; if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS) { if ((ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord, &lpValueRecord)) == ERROR_SUCCESS) { ErrorCode = RgCopyFromValueRecord(hKey, lpValueRecord, NULL, NULL, lpType, lpData, lpcbData); RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, FALSE); } else if (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32) { // // Windows 95 compatibility problem. If the "value // record" didn't exist in Windows 3.1, then it acted like it was // really a null byte REG_SZ string. This should have only been // done in RegQueryValue, but we're stuck with it now... // if (IsNullPtr(lpValueName) || *lpValueName == '\0') { if (!IsNullPtr(lpType)) *lpType = REG_SZ; if (!IsNullPtr(lpData) && *lpcbData > 0) *lpData = 0; if (!IsNullPtr(lpcbData)) *lpcbData = sizeof(char); ErrorCode = ERROR_SUCCESS; } } } RgUnlockRegistry(); return ErrorCode; UNREFERENCED_PARAMETER(lpReserved); } // // VMMRegQueryValue // // See Win32 documentation of RegQueryValue. // LONG REGAPI VMMRegQueryValue( HKEY hKey, LPCSTR lpSubKey, LPBYTE lpData, LPDWORD lpcbData ) { LONG ErrorCode; HKEY hSubKey; if ((ErrorCode = RgCreateOrOpenKey(hKey, lpSubKey, &hSubKey, LK_OPEN)) == ERROR_SUCCESS) { ErrorCode = VMMRegQueryValueEx(hSubKey, NULL, NULL, NULL, lpData, lpcbData); VMMRegCloseKey(hSubKey); } return ErrorCode; }