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

983 lines
27 KiB
C

//
// REGKNODE.C
//
// Copyright (C) Microsoft Corporation, 1995
//
#include "pch.h"
DECLARE_DEBUG_COUNT(g_RgKeynodeLockCount);
#define HAS_COMPACT_KEYNODES(lpfi) ((lpfi)-> Flags & FI_VERSION20)
#define SIZEOF_KEYNODE_BLOCK(lpfi) \
((HAS_COMPACT_KEYNODES(lpfi)) ? sizeof(KEYNODE_BLOCK) : sizeof(W95KEYNODE_BLOCK))
#define SIZEOF_FILE_KEYNODE(lpfi) \
((HAS_COMPACT_KEYNODES(lpfi)) ? sizeof(KEYNODE) : sizeof(W95KEYNODE))
#define ROUND_UP(i, basesize) (((((i) + (basesize) - 1) / (basesize))) * (basesize))
#define BLOCK_DESC_GROW_SIZE 0x400
#define W95KEYNODES_PER_PAGE (PAGESIZE / sizeof(W95KEYNODE))
typedef BOOL (INTERNAL *LPPROCESSKEYNODEPROC)(LPKEYNODE, LPW95KEYNODE);
//
// RgOffsetToIndex
//
DWORD
INTERNAL
RgOffsetToIndex(
DWORD W95KeynodeOffset
)
{
return (W95KeynodeOffset == REG_NULL) ? W95KeynodeOffset :
(W95KeynodeOffset / sizeof(W95KEYNODE));
}
//
// RgIndexToOffset
//
DWORD
INTERNAL
RgIndexToOffset(
DWORD KeynodeIndex
)
{
if (IsNullKeynodeIndex(KeynodeIndex))
return REG_NULL;
else {
if (KeynodeIndex >= 2 * W95KEYNODES_PER_PAGE) {
DWORD dwUnroundedOff = (KeynodeIndex * sizeof(W95KEYNODE))
+ sizeof(W95KEYNODE)-1;
DWORD dwRoundPage = ((dwUnroundedOff & PAGEMASK) / sizeof(W95KEYNODE))
* sizeof(W95KEYNODE);
return((dwUnroundedOff & ~PAGEMASK) + dwRoundPage);
} else {
return(((KeynodeIndex-1)*sizeof(W95KEYNODE))+sizeof(KEYNODE_HEADER));
}
}
}
//
// RgPackKeynode
//
// Packs the data from the provided W95KEYNODE to the KEYNODE structure.
//
BOOL
INTERNAL
RgPackKeynode(
LPKEYNODE lpKeynode,
LPW95KEYNODE lpW95Keynode
)
{
lpKeynode->Flags = 0;
// Don't use a switch statement here. Apparently the compiler will treat
// lpW95Keynode->W95State as an integer, so the 16-bit compiler ends up truncating
// the value.
if (lpW95Keynode->W95State == KNS_USED ||
lpW95Keynode->W95State == KNS_BIGUSED ||
lpW95Keynode->W95State == KNS_BIGUSEDEXT) {
lpKeynode->Flags = KNF_INUSE;
lpKeynode->ParentIndex = RgOffsetToIndex(lpW95Keynode->W95ParentOffset);
lpKeynode->NextIndex = RgOffsetToIndex(lpW95Keynode->W95NextOffset);
lpKeynode->ChildIndex = RgOffsetToIndex(lpW95Keynode->W95ChildOffset);
lpKeynode->KeyRecordIndex = LOWORD(lpW95Keynode->W95DatablockAddress);
lpKeynode->BlockIndex = HIWORD(lpW95Keynode->W95DatablockAddress);
lpKeynode->Hash = (WORD)lpW95Keynode->W95Hash;
if (lpW95Keynode->W95State == KNS_BIGUSED)
lpKeynode->Flags |= KNF_BIGKEYROOT;
else if (lpW95Keynode->W95State == KNS_BIGUSEDEXT)
lpKeynode->Flags |= KNF_BIGKEYEXT;
}
else if (lpW95Keynode->W95State == KNS_FREE || lpW95Keynode->W95State ==
KNS_ALLFREE) {
lpKeynode->FreeRecordSize = lpW95Keynode->W95FreeRecordSize;
lpKeynode->NextIndex = RgOffsetToIndex(lpW95Keynode->W95NextFreeOffset);
// Review this later. Previous versions of this code checked
// if the next index was REG_NULL and bailed out of the processing
// loop. It's possible to have a registry with a free keynode sitting
// in the middle of some keynode block and that keynode is the last
// in the chain. We don't want to bail out in those cases.
//
// For now, just bail out if the free record size is greater than a
// couple keynodes indicating that this is probably the last free
// record and the last record of the keynode.
if (lpKeynode-> FreeRecordSize > (sizeof(W95KEYNODE)*2))
return TRUE;
}
else {
DEBUG_OUT(("RgPackKeynode: Unrecognized state (%lx)\n", lpW95Keynode->
W95State));
}
return FALSE;
}
//
// RgUnpackKeynode
//
// Unpacks the data from the provided KEYNODE to the W95KEYNODE structure.
//
BOOL
INTERNAL
RgUnpackKeynode(
LPKEYNODE lpKeynode,
LPW95KEYNODE lpW95Keynode
)
{
if (lpKeynode->Flags & KNF_INUSE) {
if (lpKeynode->Flags & KNF_BIGKEYROOT)
lpW95Keynode->W95State = KNS_BIGUSED;
else if (lpKeynode->Flags & KNF_BIGKEYEXT)
lpW95Keynode->W95State = KNS_BIGUSEDEXT;
else
lpW95Keynode->W95State = KNS_USED;
lpW95Keynode->W95ParentOffset = RgIndexToOffset(lpKeynode->ParentIndex);
lpW95Keynode->W95NextOffset = RgIndexToOffset(lpKeynode->NextIndex);
lpW95Keynode->W95ChildOffset = RgIndexToOffset(lpKeynode->ChildIndex);
lpW95Keynode->W95Hash = lpKeynode->Hash;
// Handle Win95 registries that don't have a key record for the root
// key. The datablock address must be REG_NULL for Win95 to work.
lpW95Keynode->W95DatablockAddress = IsNullBlockIndex(lpKeynode->
BlockIndex) ? REG_NULL : MAKELONG(lpKeynode-> KeyRecordIndex,
lpKeynode-> BlockIndex);
}
else {
lpW95Keynode->W95State = KNS_FREE;
lpW95Keynode->W95FreeRecordSize = lpKeynode->FreeRecordSize;
lpW95Keynode->W95NextFreeOffset = RgIndexToOffset(lpKeynode->NextIndex);
}
return FALSE;
}
//
// RgProcessKeynodeBlock
//
// The provided callback function is called for each pair of KEYNODE and
// W95KEYNODE structures from the given keynode blocks.
//
VOID
INTERNAL
RgProcessKeynodeBlock(
DWORD dwStartOffset,
DWORD dwBlockSize,
LPKEYNODE_BLOCK lpKeynodeBlock,
LPW95KEYNODE_BLOCK lpW95KeynodeBlock,
LPPROCESSKEYNODEPROC lpfnProcessKeynode
)
{
DWORD dwCurOffset;
LPKEYNODE lpKeynode;
LPW95KEYNODE lpW95Keynode;
UINT SkipSize;
dwCurOffset = dwStartOffset;
lpW95Keynode = &lpW95KeynodeBlock->aW95KN[0];
SkipSize = (dwStartOffset == 0) ? sizeof(KEYNODE_HEADER) : 0;
for (;;) {
lpW95Keynode = (LPW95KEYNODE)(((LPBYTE)lpW95Keynode)+SkipSize);
dwCurOffset += SkipSize;
if (dwCurOffset >= dwStartOffset+dwBlockSize) {
goto Done;
}
lpKeynode = &lpKeynodeBlock->aKN[KN_INDEX_IN_BLOCK(RgOffsetToIndex(dwCurOffset))];
while ((dwCurOffset < dwStartOffset+dwBlockSize) &&
((dwCurOffset >> PAGESHIFT) == 0) ||
((dwCurOffset >> PAGESHIFT) ==
((dwCurOffset + sizeof(W95KEYNODE)) >> PAGESHIFT))) {
if (lpfnProcessKeynode(lpKeynode, lpW95Keynode)) {
goto Done;
}
dwCurOffset += sizeof(W95KEYNODE);
lpW95Keynode++;
lpKeynode++;
}
//
// Compute the number of bytes to skip to get to the next page
//
SkipSize = PAGESIZE - (UINT) (dwCurOffset & PAGEMASK);
}
Done: {};
}
//
// RgLockKeynode
//
int
INTERNAL
RgLockKeynode(
LPFILE_INFO lpFileInfo,
DWORD KeynodeIndex,
LPKEYNODE FAR* lplpKeynode
)
{
int ErrorCode;
UINT KeynodeBlockIndex;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
UINT KeynodeBlockSize;
HFILE hFile;
LPKEYNODE_BLOCK lpKeynodeBlock;
LPW95KEYNODE_BLOCK lpW95KeynodeBlock;
DWORD BlockOffset;
UINT ReadBlockSize;
KeynodeBlockIndex = KN_BLOCK_NUMBER(KeynodeIndex);
if (KeynodeBlockIndex > lpFileInfo-> KeynodeBlockCount) {
DEBUG_OUT(("RgLockKeynode: invalid keynode offset\n"));
return ERROR_BADDB;
}
//
// Is the keynode block currently in memory?
//
lpKeynodeBlockInfo = RgIndexKeynodeBlockInfoPtr(lpFileInfo,
KeynodeBlockIndex);
lpKeynodeBlock = lpKeynodeBlockInfo-> lpKeynodeBlock;
if (IsNullPtr(lpKeynodeBlock)) {
NOISE(("RgLockKeynode: "));
NOISE((lpFileInfo-> FileName));
NOISE((", block %d\n", KeynodeBlockIndex));
if (IsNullPtr((lpKeynodeBlock = (LPKEYNODE_BLOCK)
RgAllocMemory(sizeof(KEYNODE_BLOCK)))))
return ERROR_OUTOFMEMORY;
KeynodeBlockSize = SIZEOF_KEYNODE_BLOCK(lpFileInfo);
BlockOffset = (DWORD) KeynodeBlockIndex * KeynodeBlockSize;
if (BlockOffset < lpFileInfo-> KeynodeHeader.FileKnSize) {
ASSERT(!(lpFileInfo-> Flags & FI_VOLATILE));
ReadBlockSize = (UINT) min(KeynodeBlockSize, (lpFileInfo->
KeynodeHeader.FileKnSize - BlockOffset));
if ((hFile = RgOpenFile(lpFileInfo-> FileName, OF_READ)) ==
HFILE_ERROR)
goto CleanupAfterFileError;
if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
if (!RgSeekFile(hFile, sizeof(VERSION20_HEADER_PAGE) +
BlockOffset))
goto CleanupAfterFileError;
if (!RgReadFile(hFile, lpKeynodeBlock, ReadBlockSize))
goto CleanupAfterFileError;
}
else {
if (!RgSeekFile(hFile, sizeof(FILE_HEADER) + BlockOffset))
goto CleanupAfterFileError;
lpW95KeynodeBlock = (LPW95KEYNODE_BLOCK) RgLockWorkBuffer();
if (!RgReadFile(hFile, lpW95KeynodeBlock, ReadBlockSize)) {
RgUnlockWorkBuffer(lpW95KeynodeBlock);
goto CleanupAfterFileError;
}
RgProcessKeynodeBlock(BlockOffset, ReadBlockSize,
lpKeynodeBlock, lpW95KeynodeBlock, RgPackKeynode);
RgUnlockWorkBuffer(lpW95KeynodeBlock);
}
RgCloseFile(hFile);
}
lpKeynodeBlockInfo-> lpKeynodeBlock = lpKeynodeBlock;
lpKeynodeBlockInfo-> Flags = 0;
lpKeynodeBlockInfo-> LockCount = 0;
}
*lplpKeynode = &lpKeynodeBlock-> aKN[KN_INDEX_IN_BLOCK(KeynodeIndex)];
lpKeynodeBlockInfo-> Flags |= KBIF_ACCESSED;
lpKeynodeBlockInfo-> LockCount++;
INCREMENT_DEBUG_COUNT(g_RgKeynodeLockCount);
return ERROR_SUCCESS;
CleanupAfterFileError:
ErrorCode = ERROR_REGISTRY_IO_FAILED;
RgFreeMemory(lpKeynodeBlock);
if (hFile != HFILE_ERROR)
RgCloseFile(hFile);
DEBUG_OUT(("RgLockKeynode() returning error %d\n", ErrorCode));
return ErrorCode;
}
//
// RgLockInUseKeynode
//
// Wrapper for RgLockKeynode that guarantees that the returned keynode is
// marked as being in-use. If not, ERROR_BADDB is returned.
//
int
INTERNAL
RgLockInUseKeynode(
LPFILE_INFO lpFileInfo,
DWORD KeynodeIndex,
LPKEYNODE FAR* lplpKeynode
)
{
int ErrorCode;
if ((ErrorCode = RgLockKeynode(lpFileInfo, KeynodeIndex, lplpKeynode)) ==
ERROR_SUCCESS) {
if (!((*lplpKeynode)-> Flags & KNF_INUSE)) {
DEBUG_OUT(("RgLockInUseKeynode: keynode unexpectedly not marked used\n"));
RgUnlockKeynode(lpFileInfo, KeynodeIndex, FALSE);
ErrorCode = ERROR_BADDB;
}
}
return ErrorCode;
}
//
// RgUnlockKeynode
//
VOID
INTERNAL
RgUnlockKeynode(
LPFILE_INFO lpFileInfo,
DWORD KeynodeIndex,
BOOL fMarkDirty
)
{
UINT KeynodeBlockIndex;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
KeynodeBlockIndex = KN_BLOCK_NUMBER(KeynodeIndex);
ASSERT(KeynodeBlockIndex < lpFileInfo-> KeynodeBlockCount);
lpKeynodeBlockInfo = RgIndexKeynodeBlockInfoPtr(lpFileInfo,
KeynodeBlockIndex);
ASSERT(lpKeynodeBlockInfo-> LockCount > 0);
lpKeynodeBlockInfo-> LockCount--;
if (fMarkDirty) {
lpKeynodeBlockInfo-> Flags |= KBIF_DIRTY;
lpFileInfo-> Flags |= FI_DIRTY | FI_KEYNODEDIRTY;
RgDelayFlush();
}
DECREMENT_DEBUG_COUNT(g_RgKeynodeLockCount);
}
//
// RgAllocKeynode
//
int
INTERNAL
RgAllocKeynode(
LPFILE_INFO lpFileInfo,
LPDWORD lpKeynodeIndex,
LPKEYNODE FAR* lplpKeynode
)
{
int ErrorCode;
DWORD FreeKeynodeOffset;
DWORD FreeKeynodeIndex;
UINT FreeRecordSize;
UINT ExtraPadding;
UINT KeynodeBlockIndex;
UINT AllocCount;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
LPKEYNODE lpKeynode;
DWORD NextFreeKeynodeIndex;
LPKEYNODE lpNextFreeKeynode;
UINT KeynodeSize;
FreeKeynodeIndex = lpFileInfo-> KeynodeHeader.FirstFreeIndex;
// If no more free keynodes exist, then we try to extend the keynode table
// to provide more entries.
if (IsNullKeynodeIndex(FreeKeynodeIndex)) {
if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
FreeKeynodeIndex = ROUND_UP(lpFileInfo-> CurTotalKnSize, PAGESIZE) /
sizeof(KEYNODE);
FreeRecordSize = PAGESIZE;
ExtraPadding = 0;
}
else {
// Handle the special case of a new file being created: for
// uncompacted keynode tables, the first offset is immediately
// after the keynode header and the size of the free record must
// account for the size of this header.
if (lpFileInfo-> CurTotalKnSize == sizeof(KEYNODE_HEADER)) {
FreeKeynodeOffset = sizeof(KEYNODE_HEADER);
// Win95 compatiblity: Same initial table size, plus
// causes us to stress the below special grow case.
FreeRecordSize = PAGESIZE - sizeof(KEYNODE_HEADER) * 2;
ExtraPadding = 0;
}
else {
FreeKeynodeOffset = ROUND_UP(lpFileInfo-> CurTotalKnSize,
PAGESIZE);
FreeRecordSize = PAGESIZE;
ExtraPadding = (UINT) (FreeKeynodeOffset - lpFileInfo->
CurTotalKnSize);
// Handle the case of a keynode table with a non-integral
// number of pages. We'll place the new free keynode at the
// top of the existing keynode table with a size including
// the remaining bytes on the page plus a new page (effectively
// the same as Win95).
if (ExtraPadding > sizeof(W95KEYNODE) || FreeKeynodeOffset ==
PAGESIZE) {
// Although this code will work for any non-integral
// number of pages, it should ONLY occur for <4K tables.
ASSERT(FreeKeynodeOffset == PAGESIZE);
FreeRecordSize += ExtraPadding;
FreeKeynodeOffset = lpFileInfo-> CurTotalKnSize;
ExtraPadding = 0;
}
}
FreeKeynodeIndex = RgOffsetToIndex(FreeKeynodeOffset);
}
KeynodeBlockIndex = KN_BLOCK_NUMBER(FreeKeynodeIndex);
// Put in some sort of "max" count/KEYNODE_BLOCKS_PER_FILE
// check.
// Check if lpKeynodeBlockInfo is too small to hold the info for a new
// keynode block. If so, then we must grow it a bit.
if (KeynodeBlockIndex >= lpFileInfo-> KeynodeBlockInfoAllocCount) {
AllocCount = KeynodeBlockIndex + KEYNODE_BLOCK_INFO_SLACK_ALLOC;
if (IsNullPtr((lpKeynodeBlockInfo = (LPKEYNODE_BLOCK_INFO)
RgSmReAllocMemory(lpFileInfo-> lpKeynodeBlockInfo, AllocCount *
sizeof(KEYNODE_BLOCK_INFO)))))
return ERROR_OUTOFMEMORY;
ZeroMemory(lpKeynodeBlockInfo + lpFileInfo->
KeynodeBlockInfoAllocCount, (AllocCount - lpFileInfo->
KeynodeBlockInfoAllocCount) * sizeof(KEYNODE_BLOCK_INFO));
lpFileInfo-> lpKeynodeBlockInfo = lpKeynodeBlockInfo;
lpFileInfo-> KeynodeBlockInfoAllocCount = AllocCount;
}
if (KeynodeBlockIndex < lpFileInfo-> KeynodeBlockCount)
{
lpFileInfo-> CurTotalKnSize += (FreeRecordSize + ExtraPadding);
lpFileInfo-> Flags |= FI_EXTENDED;
lpFileInfo-> KeynodeHeader.FirstFreeIndex = FreeKeynodeIndex;
}
if ((ErrorCode = RgLockKeynode(lpFileInfo, FreeKeynodeIndex,
&lpKeynode)) != ERROR_SUCCESS)
return ErrorCode;
if (KeynodeBlockIndex >= lpFileInfo-> KeynodeBlockCount)
{
lpFileInfo-> KeynodeBlockCount = KeynodeBlockIndex + 1;
lpFileInfo-> CurTotalKnSize += (FreeRecordSize + ExtraPadding);
lpFileInfo-> Flags |= FI_EXTENDED;
lpFileInfo-> KeynodeHeader.FirstFreeIndex = FreeKeynodeIndex;
}
lpKeynode-> NextIndex = REG_NULL;
lpKeynode-> Flags = 0;
lpKeynode-> FreeRecordSize = FreeRecordSize;
}
else {
if ((ErrorCode = RgLockKeynode(lpFileInfo, FreeKeynodeIndex,
&lpKeynode)) != ERROR_SUCCESS)
return ErrorCode;
}
NextFreeKeynodeIndex = lpKeynode-> NextIndex;
KeynodeSize = SIZEOF_FILE_KEYNODE(lpFileInfo);
// If the free keynode record can be broken up into smaller chunks, then
// create another free record immediately after the one we're about to
// snag.
if ((lpKeynode-> FreeRecordSize >= KeynodeSize * 2) &&
(RgLockKeynode(lpFileInfo, FreeKeynodeIndex + 1, &lpNextFreeKeynode) ==
ERROR_SUCCESS)) {
// Copy the next link from the current free keynode (likely REG_NULL).
lpNextFreeKeynode-> NextIndex = NextFreeKeynodeIndex;
lpNextFreeKeynode-> Flags = 0;
lpNextFreeKeynode-> FreeRecordSize = lpKeynode-> FreeRecordSize -
KeynodeSize;
NextFreeKeynodeIndex = FreeKeynodeIndex + 1;
RgUnlockKeynode(lpFileInfo, NextFreeKeynodeIndex, TRUE);
}
lpFileInfo-> KeynodeHeader.FirstFreeIndex = NextFreeKeynodeIndex;
lpKeynode-> Flags |= KNF_INUSE;
// Mark the keynode block that holds this keynode dirty.
lpKeynodeBlockInfo = RgIndexKeynodeBlockInfoPtr(lpFileInfo,
KN_BLOCK_NUMBER(FreeKeynodeIndex));
lpKeynodeBlockInfo-> Flags |= KBIF_DIRTY;
lpFileInfo-> Flags |= FI_DIRTY | FI_KEYNODEDIRTY;
RgDelayFlush();
// WARNING: The following two statements used to be above the block that
// dirtied the keynode. The 16-bit compiler messed up and
// lpKeynodeBlockInfo ended up with a bogus offset thus corrupting random
// memory. Be sure to trace through this function if you change it!
*lpKeynodeIndex = FreeKeynodeIndex;
*lplpKeynode = lpKeynode;
return ERROR_SUCCESS;
}
//
// RgFreeKeynode
//
// Marks the specified keynode index free and adds it to the hive's free
// keynode list.
//
int
INTERNAL
RgFreeKeynode(
LPFILE_INFO lpFileInfo,
DWORD KeynodeIndex
)
{
int ErrorCode;
LPKEYNODE lpKeynode;
if ((ErrorCode = RgLockKeynode(lpFileInfo, KeynodeIndex, &lpKeynode)) ==
ERROR_SUCCESS) {
lpKeynode-> Flags &= ~(KNF_INUSE | KNF_BIGKEYROOT | KNF_BIGKEYEXT);
lpKeynode-> NextIndex = lpFileInfo-> KeynodeHeader.FirstFreeIndex;
lpKeynode-> FreeRecordSize = SIZEOF_FILE_KEYNODE(lpFileInfo);
lpFileInfo-> KeynodeHeader.FirstFreeIndex = KeynodeIndex;
RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE);
}
return ErrorCode;
}
//
// RgGetKnBlockIOInfo
//
VOID
INTERNAL
RgGetKnBlockIOInfo(
LPFILE_INFO lpFileInfo,
DWORD BaseKeynodeIndex,
UINT FAR* lpFileBlockSize,
LONG FAR* lpFileOffset
)
{
UINT FileBlockSize;
DWORD FileOffset;
DWORD BaseKeynodeOffset;
if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
FileBlockSize = sizeof(KEYNODE_BLOCK);
BaseKeynodeOffset = BaseKeynodeIndex * sizeof(KEYNODE);
if (BaseKeynodeOffset + FileBlockSize > lpFileInfo-> CurTotalKnSize)
FileBlockSize = (UINT) (lpFileInfo-> CurTotalKnSize -
BaseKeynodeOffset);
FileOffset = sizeof(VERSION20_HEADER_PAGE) + BaseKeynodeIndex *
sizeof(KEYNODE);
}
else {
FileBlockSize = sizeof(W95KEYNODE_BLOCK);
// The first keynode block of an uncompacted keynode table should
// start writing AFTER the keynode header.
if (BaseKeynodeIndex == 0) {
BaseKeynodeIndex = RgOffsetToIndex(sizeof(KEYNODE_HEADER));
FileBlockSize -= sizeof(KEYNODE_HEADER);
}
BaseKeynodeOffset = RgIndexToOffset(BaseKeynodeIndex);
if (BaseKeynodeOffset + FileBlockSize > lpFileInfo-> CurTotalKnSize)
FileBlockSize = (UINT) (lpFileInfo-> CurTotalKnSize -
BaseKeynodeOffset);
FileOffset = sizeof(FILE_HEADER) + BaseKeynodeOffset;
}
*lpFileBlockSize = FileBlockSize;
*lpFileOffset = FileOffset;
}
int
_inline
RgCopyKeynodeBlock(
LPFILE_INFO lpFileInfo,
DWORD BaseIndex,
HFILE hSrcFile,
HFILE hDestFile
)
{
UINT FileBlockSize;
LONG FileOffset;
RgGetKnBlockIOInfo(lpFileInfo, BaseIndex, &FileBlockSize, &FileOffset);
return RgCopyFileBytes(hSrcFile,
FileOffset,
hDestFile,
FileOffset,
FileBlockSize);
}
//
// RgWriteKeynodeBlock
//
int
INTERNAL
RgWriteKeynodeBlock(
LPFILE_INFO lpFileInfo,
DWORD BaseIndex,
HFILE hDestFile,
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo
)
{
int ErrorCode;
UINT FileBlockSize;
LONG FileOffset;
LPW95KEYNODE_BLOCK lpW95KeynodeBlock;
RgGetKnBlockIOInfo(lpFileInfo, BaseIndex, &FileBlockSize, &FileOffset);
ErrorCode = ERROR_REGISTRY_IO_FAILED; // Assume I/O fails
if (!RgSeekFile(hDestFile, FileOffset)) {
goto Exit;
}
if (HAS_COMPACT_KEYNODES(lpFileInfo)) {
if (RgWriteFile(hDestFile, lpKeynodeBlockInfo->lpKeynodeBlock, FileBlockSize)) {
ErrorCode = ERROR_SUCCESS;
}
} else {
LPBYTE lpWriteBlock;
lpW95KeynodeBlock = (LPW95KEYNODE_BLOCK) RgLockWorkBuffer();
RgProcessKeynodeBlock(
BaseIndex * sizeof(W95KEYNODE),
FileBlockSize,
lpKeynodeBlockInfo->lpKeynodeBlock,
lpW95KeynodeBlock,
RgUnpackKeynode);
lpWriteBlock = (LPBYTE)lpW95KeynodeBlock;
if (BaseIndex == 0) {
lpWriteBlock += sizeof(KEYNODE_HEADER);
}
if (RgWriteFile(hDestFile, lpWriteBlock, FileBlockSize)) {
ErrorCode = ERROR_SUCCESS;
}
RgUnlockWorkBuffer(lpW95KeynodeBlock);
}
Exit: ;
return(ErrorCode);
}
//
// RgWriteKeynodes
//
int
INTERNAL
RgWriteKeynodes(
LPFILE_INFO lpFileInfo,
HFILE hSrcFile,
HFILE hDestFile
)
{
DWORD SavedRootIndex;
DWORD SavedFreeIndex;
DWORD SavedFileKnSize;
BOOL fResult;
UINT KeynodeBlockIndex;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
if ((hSrcFile == HFILE_ERROR) && !(lpFileInfo->Flags & FI_KEYNODEDIRTY))
return ERROR_SUCCESS;
NOISE(("writing keynodes of "));
NOISE((lpFileInfo-> FileName));
NOISE(("\n"));
//
// Write out the keynode header. If the keynodes are not compact then
// convert to offsets before writing.
//
if (!RgSeekFile(hDestFile, sizeof(FILE_HEADER)))
return ERROR_REGISTRY_IO_FAILED;
SavedFileKnSize = lpFileInfo-> KeynodeHeader.FileKnSize;
SavedRootIndex = lpFileInfo-> KeynodeHeader.RootIndex;
SavedFreeIndex = lpFileInfo-> KeynodeHeader.FirstFreeIndex;
// Write the real size of the keynode table to disk.
lpFileInfo-> KeynodeHeader.FileKnSize = lpFileInfo-> CurTotalKnSize;
// Convert keynode indexes back to offsets temporarily for uncompacted
// keynode tables.
if (!HAS_COMPACT_KEYNODES(lpFileInfo)) {
lpFileInfo-> KeynodeHeader.RootIndex = RgIndexToOffset(lpFileInfo->
KeynodeHeader.RootIndex);
lpFileInfo-> KeynodeHeader.FirstFreeIndex = RgIndexToOffset(lpFileInfo->
KeynodeHeader.FirstFreeIndex);
}
fResult = RgWriteFile(hDestFile, &lpFileInfo-> KeynodeHeader,
sizeof(KEYNODE_HEADER));
lpFileInfo-> KeynodeHeader.FileKnSize = SavedFileKnSize;
lpFileInfo-> KeynodeHeader.RootIndex = SavedRootIndex;
lpFileInfo-> KeynodeHeader.FirstFreeIndex = SavedFreeIndex;
if (!fResult)
return ERROR_REGISTRY_IO_FAILED;
//
// Now loop through each block.
//
lpKeynodeBlockInfo = lpFileInfo-> lpKeynodeBlockInfo;
for (KeynodeBlockIndex = 0; KeynodeBlockIndex < lpFileInfo->
KeynodeBlockCount; KeynodeBlockIndex++, lpKeynodeBlockInfo++) {
DWORD BaseKeynodeIndex = KeynodeBlockIndex * KEYNODES_PER_BLOCK;
if (!IsNullPtr(lpKeynodeBlockInfo-> lpKeynodeBlock)) {
if (hSrcFile != HFILE_ERROR || lpKeynodeBlockInfo-> Flags &
KBIF_DIRTY) {
if (RgWriteKeynodeBlock(lpFileInfo, BaseKeynodeIndex, hDestFile,
lpKeynodeBlockInfo) != ERROR_SUCCESS)
return ERROR_REGISTRY_IO_FAILED;
}
}
else {
if (hSrcFile != HFILE_ERROR) {
if (RgCopyKeynodeBlock(lpFileInfo, BaseKeynodeIndex, hSrcFile,
hDestFile) != ERROR_SUCCESS)
return ERROR_REGISTRY_IO_FAILED;
}
}
}
return ERROR_SUCCESS;
}
//
// RgWriteKeynodesComplete
//
// Called after a file has been successfully written. We can now safely clear
// all dirty flags and update our state information with the knowledge that
// the file is in a consistent state.
//
VOID
INTERNAL
RgWriteKeynodesComplete(
LPFILE_INFO lpFileInfo
)
{
UINT BlocksLeft;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
lpFileInfo-> Flags &= ~FI_KEYNODEDIRTY;
lpFileInfo-> KeynodeHeader.FileKnSize = lpFileInfo-> CurTotalKnSize;
for (BlocksLeft = lpFileInfo-> KeynodeBlockCount, lpKeynodeBlockInfo =
lpFileInfo-> lpKeynodeBlockInfo; BlocksLeft > 0; BlocksLeft--,
lpKeynodeBlockInfo++)
lpKeynodeBlockInfo-> Flags &= ~KBIF_DIRTY;
}
//
// RgSweepKeynodes
//
// Makes a pass through all the present keynode blocks of the given FILE_INFO
// structure and discards keynode blocks that have not been accessed since the
// last sweep.
//
VOID
INTERNAL
RgSweepKeynodes(
LPFILE_INFO lpFileInfo
)
{
UINT BlocksLeft;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
for (BlocksLeft = lpFileInfo-> KeynodeBlockCount, lpKeynodeBlockInfo =
lpFileInfo-> lpKeynodeBlockInfo; BlocksLeft > 0; BlocksLeft--,
lpKeynodeBlockInfo++) {
if (!IsNullPtr(lpKeynodeBlockInfo-> lpKeynodeBlock)) {
if (((lpKeynodeBlockInfo-> Flags & (KBIF_ACCESSED | KBIF_DIRTY)) ==
0) && (lpKeynodeBlockInfo-> LockCount == 0)) {
RgFreeMemory(lpKeynodeBlockInfo-> lpKeynodeBlock);
lpKeynodeBlockInfo-> lpKeynodeBlock = NULL;
}
lpKeynodeBlockInfo-> Flags &= ~KBIF_ACCESSED;
}
}
}
#ifdef VXD
#pragma VxD_RARE_CODE_SEG
#endif
//
// RgInitKeynodeInfo
//
// Initializes fields in the provided FILE_INFO related to the keynode table.
//
int
INTERNAL
RgInitKeynodeInfo(
LPFILE_INFO lpFileInfo
)
{
UINT KeynodeBlockSize;
UINT BlockCount;
UINT AllocCount;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
KeynodeBlockSize = SIZEOF_KEYNODE_BLOCK(lpFileInfo);
BlockCount = (UINT) ((DWORD) (lpFileInfo-> KeynodeHeader.FileKnSize +
KeynodeBlockSize - 1) / (DWORD) KeynodeBlockSize);
AllocCount = BlockCount + KEYNODE_BLOCK_INFO_SLACK_ALLOC;
if (IsNullPtr((lpKeynodeBlockInfo = (LPKEYNODE_BLOCK_INFO)
RgSmAllocMemory(AllocCount * sizeof(KEYNODE_BLOCK_INFO)))))
return ERROR_OUTOFMEMORY;
ZeroMemory(lpKeynodeBlockInfo, AllocCount * sizeof(KEYNODE_BLOCK_INFO));
lpFileInfo-> lpKeynodeBlockInfo = lpKeynodeBlockInfo;
lpFileInfo-> KeynodeBlockCount = BlockCount;
lpFileInfo-> KeynodeBlockInfoAllocCount = AllocCount;
lpFileInfo-> KeynodeHeader.Flags &= ~(KHF_DIRTY | KHF_EXTENDED |
KHF_HASCHECKSUM);
// Convert file offsets to index values for uncompressed files
if (!HAS_COMPACT_KEYNODES(lpFileInfo)) {
lpFileInfo-> KeynodeHeader.RootIndex = RgOffsetToIndex(lpFileInfo->
KeynodeHeader.RootIndex);
lpFileInfo-> KeynodeHeader.FirstFreeIndex = RgOffsetToIndex(lpFileInfo->
KeynodeHeader.FirstFreeIndex);
}
lpFileInfo-> CurTotalKnSize = lpFileInfo-> KeynodeHeader.FileKnSize;
return ERROR_SUCCESS;
}