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

240 lines
6.4 KiB
C

//
// REGEKEY.C
//
// Copyright (C) Microsoft Corporation, 1995
//
// Implementation of RegEnumKey and supporting functions.
//
#include "pch.h"
//
// RgLookupKeyByIndex
//
// lpKeyName, points to a buffer that receives the name of the subkey,
// including the null terminator. May be NULL.
// lpcbKeyName, on entry, specifies the size in characters of the buffer
// pointed to be lpKeyName, and on return, specifies the size of the
// indexed subkey. May not be NULL.
//
int
INTERNAL
RgLookupKeyByIndex(
HKEY hKey,
UINT Index,
LPSTR lpKeyName,
LPDWORD lpcbKeyName,
UINT Flags
)
{
int ErrorCode;
LPFILE_INFO lpFileInfo;
UINT KeysToSkip;
DWORD KeynodeIndex;
DWORD TempOffset;
LPKEYNODE lpKeynode;
LPKEY_RECORD lpKeyRecord;
#ifdef WANT_HIVE_SUPPORT
LPHIVE_INFO lpHiveInfo;
#endif
#ifdef REALMODE
BOOL secondTry;
#endif
lpFileInfo = hKey-> lpFileInfo;
KeysToSkip = Index;
//
// Check if we've cached the keynode index of the last key index
// (confusing?) from a previous call to this function. If so, then we can
// skip ahead a bit and avoid touching a bunch of keynode pages.
//
if ((hKey-> Flags & KEYF_ENUMKEYCACHED) &&
(!(hKey-> Flags & KEYF_ENUMEXTENTCACHED) == !(Flags & LK_BIGKEYEXT)) &&
(Index >= hKey-> LastEnumKeyIndex)) {
KeysToSkip -= hKey-> LastEnumKeyIndex;
KeynodeIndex = hKey-> LastEnumKeyKeynodeIndex;
}
else
KeynodeIndex = hKey-> ChildKeynodeIndex;
//
// Loop over the child keys of this key until we find our index or run out
// of children.
//
while (!IsNullKeynodeIndex(KeynodeIndex)) {
#ifdef REALMODE
secondTry = FALSE;
tryAgain:
#endif // REALMODE
if ((ErrorCode = RgLockInUseKeynode(lpFileInfo, KeynodeIndex,
&lpKeynode)) != ERROR_SUCCESS)
return ErrorCode;
ASSERT(hKey-> KeynodeIndex == lpKeynode-> ParentIndex);
if (!(Flags & LK_BIGKEYEXT) == !(lpKeynode-> Flags & KNF_BIGKEYEXT) &&
KeysToSkip == 0) {
if ((ErrorCode = RgLockKeyRecord(lpFileInfo, lpKeynode-> BlockIndex,
(BYTE) lpKeynode-> KeyRecordIndex, &lpKeyRecord)) ==
ERROR_SUCCESS) {
if (!IsNullPtr(lpKeyName)) {
if (*lpcbKeyName <= lpKeyRecord-> NameLength)
ErrorCode = ERROR_MORE_DATA;
else {
MoveMemory(lpKeyName, lpKeyRecord-> Name, lpKeyRecord->
NameLength);
lpKeyName[lpKeyRecord-> NameLength] = '\0';
}
}
// Does not include terminating null.
*lpcbKeyName = lpKeyRecord-> NameLength;
RgUnlockDatablock(lpFileInfo, lpKeynode-> BlockIndex, FALSE);
}
#ifdef REALMODE
else if (!secondTry)
{
// What happens in real mode, is that we get wedged with the
// Keynode block allocated and locked in the middle of the free
// space, and there is not a free block large enough for the data block.
// We have already free'd up everything that isn't locked.
// So, by unlocking and freeing the Keynode block and then restarting
// the operation, the Keynode block gets allocated at the bottom of the
// heap, leaving room for the data block.
secondTry = TRUE;
RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
RgEnumFileInfos(RgSweepFileInfo);
RgEnumFileInfos(RgSweepFileInfo);
goto tryAgain;
}
#endif // REALMODE
RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
// Cache our current position because the caller is likely to turn
// around and ask for the next index.
hKey-> LastEnumKeyIndex = Index;
hKey-> LastEnumKeyKeynodeIndex = KeynodeIndex;
hKey-> Flags |= KEYF_ENUMKEYCACHED;
if (Flags & LK_BIGKEYEXT)
hKey-> Flags |= KEYF_ENUMEXTENTCACHED;
else
hKey-> Flags &= ~KEYF_ENUMEXTENTCACHED;
return ErrorCode;
}
TempOffset = lpKeynode-> NextIndex;
RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
KeynodeIndex = TempOffset;
if (!(Flags & LK_BIGKEYEXT) == !(lpKeynode-> Flags & KNF_BIGKEYEXT))
{
KeysToSkip--;
}
}
#ifdef WANT_HIVE_SUPPORT
//
// Loop over the hives of this key until we find our index or run out of
// hives.
//
if (hKey-> Flags & KEYF_HIVESALLOWED) {
lpHiveInfo = hKey-> lpFileInfo-> lpHiveInfoList;
while (!IsNullPtr(lpHiveInfo)) {
if (KeysToSkip == 0) {
ErrorCode = ERROR_SUCCESS;
if (!IsNullPtr(lpKeyName)) {
if (*lpcbKeyName <= lpHiveInfo-> NameLength)
ErrorCode = ERROR_MORE_DATA;
else {
MoveMemory(lpKeyName, lpHiveInfo-> Name, lpHiveInfo->
NameLength);
lpKeyName[lpHiveInfo-> NameLength] = '\0';
}
}
// Does not include terminating null.
*lpcbKeyName = lpHiveInfo-> NameLength;
// We don't worry about the enum key cache if we find a
// hit in this code. This is a rare case and already the cache
// that we do have is much better then Win95.
return ErrorCode;
}
lpHiveInfo = lpHiveInfo-> lpNextHiveInfo;
KeysToSkip--;
}
}
#endif
return ERROR_NO_MORE_ITEMS;
}
//
// VMMRegEnumKey
//
// See Win32 documentation for a description of the behavior.
//
LONG
REGAPI
VMMRegEnumKey(
HKEY hKey,
DWORD Index,
LPSTR lpKeyName,
DWORD cbKeyName
)
{
int ErrorCode;
if (IsBadHugeWritePtr(lpKeyName, cbKeyName))
return ERROR_INVALID_PARAMETER;
if (IsEnumIndexTooBig(Index))
return ERROR_NO_MORE_ITEMS;
if (!RgLockRegistry())
return ERROR_LOCK_FAILED;
if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS)
ErrorCode = RgLookupKeyByIndex(hKey, (UINT) Index, lpKeyName,
&cbKeyName, 0);
RgUnlockRegistry();
return ErrorCode;
}