windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/common/regw32d/regsval.c
2020-09-26 16:20:57 +08:00

592 lines
18 KiB
C

//
// REGSVAL.C
//
// Copyright (C) Microsoft Corporation, 1995
//
// Implementation of RegSetValue, RegSetValueEx and supporting functions.
//
#include "pch.h"
//
// RgReAllocKeyRecord
//
int
INTERNAL
RgReAllocKeyRecord(
HKEY hKey,
DWORD Length,
LPKEY_RECORD FAR* lplpKeyRecord
)
{
int ErrorCode;
LPKEY_RECORD lpOldKeyRecord;
UINT BlockIndex;
UINT KeyRecordIndex;
LPDATABLOCK_INFO lpOldDatablockInfo;
LPKEYNODE lpKeynode;
if (Length > MAXIMUM_KEY_RECORD_SIZE) {
return ERROR_BIGKEY_NEEDED; // A big key is required
}
lpOldKeyRecord = *lplpKeyRecord;
BlockIndex = HIWORD(lpOldKeyRecord-> DatablockAddress);
KeyRecordIndex = LOWORD(lpOldKeyRecord-> DatablockAddress);
//
// Check if we can simply extend this key record by taking space from an
// adjacent free record.
//
if (RgExtendKeyRecord(hKey-> lpFileInfo, BlockIndex, (UINT) Length,
lpOldKeyRecord) == ERROR_SUCCESS)
return ERROR_SUCCESS;
//
// Check if there's enough space in the datablock lpCurrKeyRecord is in to
// contain a key record of the specified size. If so, then we don't have
// to dirty the keynode.
//
if (RgAllocKeyRecordFromDatablock(hKey-> lpFileInfo, BlockIndex,
(UINT) Length, lplpKeyRecord) == ERROR_SUCCESS) {
// After an alloc, we must refetch these pointers because they may be
// invalid.
lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
BlockIndex);
lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
KeyRecordIndex);
// Transfer all the data to the new record, except for the allocated
// size which is already correctly set.
MoveMemory(&(*lplpKeyRecord)-> DatablockAddress, &lpOldKeyRecord->
DatablockAddress, SmallDword(lpOldKeyRecord-> RecordSize) -
sizeof(DWORD));
RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
// Update the key record table to point to the new key record.
lpOldDatablockInfo-> lpKeyRecordTable[KeyRecordIndex] =
(KEY_RECORD_TABLE_ENTRY) ((LPBYTE) (*lplpKeyRecord) -
(LPBYTE) lpOldDatablockInfo-> lpDatablockHeader);
return ERROR_SUCCESS;
}
//
// Check if we can allocate a key record from another datablock. If so,
// then copy the key to the other datablock and update the keynode.
//
if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
&lpKeynode) == ERROR_SUCCESS) {
if ((ErrorCode = RgAllocKeyRecord(hKey-> lpFileInfo, (UINT) Length,
lplpKeyRecord)) == ERROR_SUCCESS) {
// After an alloc, we must refetch these pointers because they may
// be invalid.
lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
BlockIndex);
lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
KeyRecordIndex);
// Transfer all the data to the new record, except for the
// allocated size which is already correctly set.
MoveMemory(&(*lplpKeyRecord)-> RecordSize, &lpOldKeyRecord->
RecordSize, SmallDword(lpOldKeyRecord-> RecordSize) -
(sizeof(DWORD) * 2));
RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
RgFreeKeyRecordIndex(lpOldDatablockInfo, KeyRecordIndex);
// Unlock the old datablock.
RgUnlockDatablock(hKey-> lpFileInfo, BlockIndex, TRUE);
// Update the open key and keynode to point to the key record in
// the new datablock.
hKey-> BlockIndex = (*lplpKeyRecord)-> BlockIndex;
hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex;
lpKeynode-> BlockIndex = hKey-> BlockIndex;
hKey-> KeyRecordIndex = (BYTE) (*lplpKeyRecord)-> KeyRecordIndex;
lpKeynode-> KeyRecordIndex = hKey-> KeyRecordIndex;
}
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
return ErrorCode;
}
return ERROR_OUTOFMEMORY;
}
//
// RgSetValue
// (BIGKEY aware)
//
int
INTERNAL
RgSetValue(
HKEY hKey,
LPCSTR lpValueName,
DWORD Type,
LPBYTE lpData,
UINT cbData
)
{
int ErrorCode;
HKEY hKeyExtent;
UINT Index;
LPSTR ExtentKeyName;
DWORD cbExtentKeyName;
WORD NameID = 1;
WORD MaxNameID = 0;
LPKEY_RECORD lpKeyRecord;
LPVALUE_RECORD lpValueRecord;
LPKEYNODE lpKeynode;
BOOL fTryRoot = FALSE;
ErrorCode = RgSetValueStd(hKey, lpValueName, Type, lpData, cbData, FALSE);
if (ErrorCode == ERROR_BIGKEY_NEEDED)
{
//
// Couldn't fit the value in the key, make it a big key
// (if it isn't one already)
//
// First delete its old value if it exists
ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
&lpValueRecord);
if (ErrorCode == ERROR_SUCCESS)
{
// If a value record already existed, and it was not in the root of the big key
// then we should try inserting the new value record into the root, after deleting
// it from its old location.
if (hKey-> BigKeyLockedBlockIndex != hKey-> BlockIndex)
fTryRoot = TRUE;
RgDeleteValueRecord(lpKeyRecord, lpValueRecord);
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, TRUE);
}
else if (ErrorCode != ERROR_CANTREAD16_FILENOTFOUND32) {
return ERROR_OUTOFMEMORY;
}
if (IsNullPtr(ExtentKeyName = RgSmAllocMemory(MAXIMUM_SUB_KEY_LENGTH)))
return ERROR_OUTOFMEMORY;
// Second, search for room in each of the big key's extents
// (we should never mark the root with an LK_BIGKEYEXT, otherwise it won't be found
// by RgLookupKey and RgLookupKeyByIndex)
if ((hKey-> Flags & KEYF_BIGKEYROOT)) {
if (fTryRoot) {
// This happens if the value record previously existed in a big key extension,
// but the new value record doesn't fit in the same extension, so we want to try
// the root of the big key.
if ((ErrorCode = RgSetValueStd(hKey, lpValueName, Type, lpData, cbData, TRUE)) ==
ERROR_SUCCESS) {
goto lFreeKeyName;
}
}
Index = 0;
do {
cbExtentKeyName = MAXIMUM_SUB_KEY_LENGTH;
if (RgLookupKeyByIndex(hKey, Index++, ExtentKeyName, &cbExtentKeyName, LK_BIGKEYEXT) !=
ERROR_SUCCESS) {
goto lGrowKey;
}
NameID = RgAtoW(ExtentKeyName);
if (NameID > MaxNameID)
MaxNameID = NameID;
if (RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_OPEN | LK_BIGKEYEXT) != ERROR_SUCCESS) {
goto lGrowKey;
}
ErrorCode = RgSetValueStd(hKeyExtent, lpValueName, Type, lpData, cbData, TRUE);
RgDestroyKeyHandle(hKeyExtent);
} while (ErrorCode == ERROR_BIGKEY_NEEDED);
goto lFreeKeyName;
}
// Third, make it a big key, or if it is a big key, then grow it
lGrowKey:
// Create a unique name for the big key extent
if (MaxNameID)
NameID = MaxNameID + 1;
RgWtoA(NameID, ExtentKeyName);
if ((ErrorCode = RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_CREATE)) ==
ERROR_SUCCESS) {
// Mark the parent as the big key root, if it isn't already
if (!(hKey-> Flags & KEYF_BIGKEYROOT))
{
if ((ErrorCode = RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
&lpKeynode)) != ERROR_SUCCESS)
goto lFreeKeyName;
lpKeynode-> Flags |= KNF_BIGKEYROOT;
hKey-> Flags |= KEYF_BIGKEYROOT;
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
}
// Mark the new key as a big key extent
if ((ErrorCode = RgLockInUseKeynode(hKeyExtent-> lpFileInfo, hKeyExtent-> KeynodeIndex,
&lpKeynode)) != ERROR_SUCCESS)
goto lFreeKeyName;
lpKeynode-> Flags |= KNF_BIGKEYEXT;
RgUnlockKeynode(hKeyExtent-> lpFileInfo, hKeyExtent-> KeynodeIndex, TRUE);
// Now add the value record to the new key
ErrorCode = RgSetValueStd(hKeyExtent, lpValueName, Type, lpData, cbData, TRUE);
ASSERT(ErrorCode != ERROR_BIGKEY_NEEDED);
RgDestroyKeyHandle(hKeyExtent);
}
lFreeKeyName:
RgSmFreeMemory(ExtentKeyName);
if (ErrorCode == ERROR_BIGKEY_NEEDED)
ErrorCode = ERROR_OUTOFMEMORY;
}
return ErrorCode;
}
//
// RgSetValueStd
//
int
INTERNAL
RgSetValueStd(
HKEY hKey,
LPCSTR lpValueName,
DWORD Type,
LPBYTE lpData,
UINT cbData,
BOOL fBigKeyExtent
)
{
int ErrorCode;
UINT ValueNameLength;
UINT NewValueRecordLength;
LPKEY_RECORD lpKeyRecord;
LPVALUE_RECORD lpValueRecord;
UINT CurrentValueRecordLength;
LPBYTE lpDestination;
UINT BytesToExtend;
UINT TempCount;
LPKEYNODE lpKeynode;
ValueNameLength = (IsNullPtr(lpValueName) ? 0 : (UINT) StrLen(lpValueName));
if (ValueNameLength > MAXIMUM_VALUE_NAME_LENGTH - 1)
return ERROR_INVALID_PARAMETER;
NewValueRecordLength = sizeof(VALUE_RECORD) + ValueNameLength + cbData - 1;
if (!fBigKeyExtent) {
ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
&lpValueRecord);
}
else {
// If we didn't find it searching from the root of a bigkey, then we won't
// find it beginning from an extent.
ErrorCode = ERROR_CANTREAD16_FILENOTFOUND32;
}
//
// A value with this name already exists, so update the existing
// VALUE_RECORD with the new information.
//
if (ErrorCode == ERROR_SUCCESS) {
CurrentValueRecordLength = sizeof(VALUE_RECORD) + lpValueRecord->
NameLength + lpValueRecord-> DataLength - 1;
// Is the value record staying the same?
if (NewValueRecordLength == CurrentValueRecordLength) {
if (lpValueRecord-> DataLength == cbData && lpValueRecord->
DataType == Type && CompareMemory((LPBYTE) lpValueRecord->
Name + ValueNameLength, lpData, cbData) == 0) {
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, FALSE);
return ERROR_SUCCESS;
}
}
// Is the value record shrinking?
if (NewValueRecordLength < CurrentValueRecordLength) {
lpKeyRecord-> RecordSize -= (CurrentValueRecordLength -
NewValueRecordLength);
}
// Is the value record growing?
else if (NewValueRecordLength > CurrentValueRecordLength) {
BytesToExtend = NewValueRecordLength - CurrentValueRecordLength;
// Does the value record fit in the allocated key size?
if (BytesToExtend > SmallDword(lpKeyRecord-> AllocatedSize) -
SmallDword(lpKeyRecord-> RecordSize)) {
TempCount = (LPBYTE) lpValueRecord - (LPBYTE) lpKeyRecord;
// Grow the key record
if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
RecordSize + BytesToExtend, &lpKeyRecord)) !=
ERROR_SUCCESS) {
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex,
FALSE);
return ErrorCode;
}
lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
TempCount);
}
lpKeyRecord-> RecordSize += BytesToExtend;
}
lpDestination = (LPBYTE) lpValueRecord + NewValueRecordLength;
TempCount = (UINT) ((LPBYTE) lpKeyRecord + SmallDword(lpKeyRecord->
RecordSize) - lpDestination);
if (TempCount > 0) {
MoveMemory(lpDestination, (LPBYTE) lpValueRecord +
CurrentValueRecordLength, TempCount);
}
}
//
// No value exists with this name. Place a new VALUE_RECORD at the end of
// the KEY_RECORD.
//
else if (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32) {
// Handle Win95 registries that don't have a key record for the root
// key. We don't check if this is really the root key, but it doesn't
// matter much.
if (IsNullBlockIndex(hKey-> BlockIndex)) {
if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
&lpKeynode) != ERROR_SUCCESS)
goto LockKeynodeFailed;
if (RgAllocKeyRecord(hKey-> lpFileInfo, sizeof(KEY_RECORD) +
NewValueRecordLength, &lpKeyRecord) != ERROR_SUCCESS) {
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, FALSE);
LockKeynodeFailed:
TRAP();
return ERROR_CANTOPEN; // Win95 compatibility
}
lpKeyRecord-> RecordSize = sizeof(KEY_RECORD);
lpKeyRecord-> NameLength = 1; // Win95 compatibility
lpKeyRecord-> Name[0] = '\0'; // Win95 compatibility
lpKeyRecord-> ValueCount = 0;
lpKeyRecord-> ClassLength = 0;
lpKeyRecord-> Reserved = 0;
lpKeynode-> BlockIndex = lpKeyRecord-> BlockIndex;
lpKeynode-> KeyRecordIndex = lpKeyRecord-> KeyRecordIndex;
hKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
hKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
ErrorCode = ERROR_SUCCESS;
goto AddValueRecord;
}
if ((ErrorCode = RgLockKeyRecord(hKey-> lpFileInfo, hKey-> BlockIndex,
hKey-> KeyRecordIndex, &lpKeyRecord)) == ERROR_SUCCESS) {
if (NewValueRecordLength > SmallDword(lpKeyRecord-> AllocatedSize) -
SmallDword(lpKeyRecord-> RecordSize)) {
if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
RecordSize + NewValueRecordLength, &lpKeyRecord)) !=
ERROR_SUCCESS) {
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex,
FALSE);
return ErrorCode;
}
}
AddValueRecord:
hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex;
lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
SmallDword(lpKeyRecord-> RecordSize));
lpKeyRecord-> RecordSize += NewValueRecordLength;
lpKeyRecord-> ValueCount++;
}
}
//
// If we're successful at this point, then lpValueRecord is valid and we
// should copy the data into this record.
//
if (ErrorCode == ERROR_SUCCESS) {
lpValueRecord-> DataType = Type;
lpValueRecord-> NameLength = (WORD) ValueNameLength;
MoveMemory(lpValueRecord-> Name, lpValueName, ValueNameLength);
lpValueRecord-> DataLength = (WORD) cbData;
MoveMemory((LPBYTE) lpValueRecord-> Name + ValueNameLength, lpData,
cbData);
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, TRUE);
}
return ErrorCode;
}
//
// VMMRegSetValueEx
//
// See Win32 documentation of RegSetValueEx.
//
LONG
REGAPI
VMMRegSetValueEx(
HKEY hKey,
LPCSTR lpValueName,
DWORD Reserved,
DWORD Type,
LPBYTE lpData,
DWORD cbData
)
{
int ErrorCode;
if (IsBadOptionalStringPtr(lpValueName, (UINT) -1))
return ERROR_INVALID_PARAMETER;
//
// bad Windows 95 compatibility problem. If the type is REG_SZ,
// then override cbData with the length of the string pointed to by lpData.
// This should have only been done in RegSetValue, but we're stuck with it
// now...
//
if (Type == REG_SZ) {
if (IsBadStringPtr(lpData, (UINT) -1))
return ERROR_INVALID_PARAMETER;
cbData = StrLen(lpData);
// Must leave room for the null terminator
if (cbData >= MAXIMUM_DATA_LENGTH)
return ERROR_INVALID_PARAMETER;
}
else {
if (cbData > 0 && IsBadHugeReadPtr(lpData, cbData))
return ERROR_INVALID_PARAMETER;
}
if (cbData > MAXIMUM_DATA_LENGTH)
return ERROR_INVALID_PARAMETER;
if (!RgLockRegistry())
return ERROR_LOCK_FAILED;
if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS) {
if (IsDynDataKey(hKey) || (hKey-> lpFileInfo-> Flags & FI_READONLY))
ErrorCode = ERROR_ACCESS_DENIED;
else {
if ((ErrorCode = RgSetValue(hKey, lpValueName, Type, lpData,
(UINT) cbData)) == ERROR_SUCCESS) {
RgSignalWaitingNotifies(hKey-> lpFileInfo, hKey-> KeynodeIndex,
REG_NOTIFY_CHANGE_LAST_SET);
}
}
}
RgUnlockRegistry();
return ErrorCode;
UNREFERENCED_PARAMETER(Reserved);
}
//
// VMMRegSetValue
//
// See Win32 documentation of RegSetValue.
//
LONG
REGAPI
VMMRegSetValue(
HKEY hKey,
LPCSTR lpSubKey,
DWORD Type,
LPBYTE lpData,
DWORD cbData
)
{
LONG ErrorCode;
HKEY hSubKey;
if ((ErrorCode = RgCreateOrOpenKey(hKey, lpSubKey, &hSubKey, LK_CREATE)) ==
ERROR_SUCCESS) {
ErrorCode = VMMRegSetValueEx(hSubKey, NULL, 0, REG_SZ, lpData, 0);
VMMRegCloseKey(hSubKey);
}
return ErrorCode;
UNREFERENCED_PARAMETER(Type);
UNREFERENCED_PARAMETER(cbData);
}