|
|
//
// 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) { 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; }
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) {
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);
// 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-> KeynodeBlockCount = KeynodeBlockIndex + 1;
lpFileInfo-> CurTotalKnSize += (FreeRecordSize + ExtraPadding); lpFileInfo-> Flags |= FI_EXTENDED; lpFileInfo-> KeynodeHeader.FirstFreeIndex = FreeKeynodeIndex;
if ((ErrorCode = RgLockKeynode(lpFileInfo, FreeKeynodeIndex, &lpKeynode)) != ERROR_SUCCESS) return ErrorCode;
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; 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;
}
|