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

789 lines
22 KiB
C

//
// REGFINFO.C
//
// Copyright (C) Microsoft Corporation, 1995
//
#include "pch.h"
LPFILE_INFO g_RgFileInfoList = NULL;
const char g_RgDotBackslashPath[] = ".\\";
#ifdef VXD
#pragma VxD_RARE_CODE_SEG
#endif
//
// RgCreateFileInfoNew
//
// If CFIN_VOLATILE is specified, then we skip trying to create the backing
// store for the FILE_INFO. lpFileName should point at a null byte so we can
// initialize the FILE_INFO properly.
//
// CFIN_PRIMARY and CFIN_SECONDARY are used to determine the FHT_* constant
// to put in the file header.
//
int
INTERNAL
RgCreateFileInfoNew(
LPFILE_INFO FAR* lplpFileInfo,
LPCSTR lpFileName,
UINT Flags
)
{
int ErrorCode;
LPFILE_INFO lpFileInfo;
HFILE hFile;
LPKEYNODE lpKeynode;
DWORD KeynodeIndex;
if (IsNullPtr((lpFileInfo = (LPFILE_INFO)
RgSmAllocMemory(sizeof(FILE_INFO) + StrLen(lpFileName))))) {
ErrorCode = ERROR_OUTOFMEMORY;
goto ErrorReturn;
}
ZeroMemory(lpFileInfo, sizeof(FILE_INFO));
StrCpy(lpFileInfo-> FileName, lpFileName);
// For volatile FILE_INFOs, we obviously don't need to create the backing
// store.
if (!(Flags & CFIN_VOLATILE)) {
// Attempt to the create the given filename.
if ((hFile = RgCreateFile(lpFileName)) == HFILE_ERROR) {
ErrorCode = ERROR_REGISTRY_IO_FAILED;
goto ErrorDestroyFileInfo;
}
RgCloseFile(hFile);
}
lpFileInfo-> Flags = FI_DIRTY | FI_KEYNODEDIRTY;
// lpFileInfo-> lpHiveInfoList = NULL;
// lpFileInfo-> lpParentFileInfo = NULL;
// lpFileInfo-> lpNotifyChangeList = NULL;
// lpFileInfo-> lpKeynodeBlockInfo = NULL;
// lpFileInfo-> NumKeynodeBlocks = 0;
// lpFileInfo-> NumAllocKNBlocks = 0;
// lpFileInfo-> CurTotalKnSize = 0;
// lpFileInfo-> lpDatablockInfo = NULL;
// lpFileInfo-> DatablockInfoAllocCount = 0;
if (Flags & CFIN_VOLATILE)
lpFileInfo-> Flags |= FI_VOLATILE;
// Initialize the file header.
lpFileInfo-> FileHeader.Signature = FH_SIGNATURE;
// If we're using compact keynodes, up the version number to make sure
// Win95 doesn't try to load this hive.
if (Flags & CFIN_VERSION20) {
lpFileInfo-> FileHeader.Version = FH_VERSION20;
lpFileInfo-> Flags |= FI_VERSION20;
}
else {
lpFileInfo-> FileHeader.Version = FH_VERSION10;
}
// lpFileInfo-> FileHeader.Size = 0;
// lpFileInfo-> FileHeader.Checksum = 0;
// lpFileInfo-> FileHeader.BlockCount = 0;
lpFileInfo-> FileHeader.Flags = FHF_DIRTY;
lpFileInfo-> FileHeader.Type = ((Flags & CFIN_SECONDARY) ? FHT_SECONDARY :
FHT_PRIMARY);
// Initialize the keynode header.
lpFileInfo-> KeynodeHeader.Signature = KH_SIGNATURE;
// lpFileInfo-> KeynodeHeader.FileKnSize = 0;
lpFileInfo-> KeynodeHeader.RootIndex = REG_NULL;
lpFileInfo-> KeynodeHeader.FirstFreeIndex = REG_NULL;
lpFileInfo-> KeynodeHeader.Flags = KHF_DIRTY | KHF_NEWHASH;
// lpFileInfo-> KeynodeHeader.Checksum = 0;
// Init the keynode data structures.
if ((ErrorCode = RgInitKeynodeInfo(lpFileInfo)) != ERROR_SUCCESS)
goto ErrorDeleteFile;
// For uncompacted keynode tables, the keynode table now includes at least
// the header itself.
if (!(lpFileInfo-> Flags & FI_VERSION20))
lpFileInfo-> CurTotalKnSize = sizeof(KEYNODE_HEADER);
// Init the datablock data structures.
if ((ErrorCode = RgInitDatablockInfo(lpFileInfo, HFILE_ERROR)) !=
ERROR_SUCCESS)
goto ErrorDeleteFile;
// Allocate the keynode for the root of the file.
if ((ErrorCode = RgAllocKeynode(lpFileInfo, &KeynodeIndex, &lpKeynode)) !=
ERROR_SUCCESS)
goto ErrorDeleteFile;
lpFileInfo-> KeynodeHeader.RootIndex = KeynodeIndex;
lpKeynode-> ParentIndex = REG_NULL;
lpKeynode-> NextIndex = REG_NULL;
lpKeynode-> ChildIndex = REG_NULL;
lpKeynode-> Hash = 0;
// Note that we don't allocate a key record for this root keynode. Win95
// didn't do this either, so we already must handle this case in code that
// needs a key record. Our code is smaller if we just don't allocate this
// key record which is rarely ever used anyway...
lpKeynode-> BlockIndex = NULL_BLOCK_INDEX;
RgUnlockKeynode(lpFileInfo, KeynodeIndex, TRUE);
if ((ErrorCode = RgFlushFileInfo(lpFileInfo)) != ERROR_SUCCESS)
goto ErrorDeleteFile;
// Link this FILE_INFO into the global file info list.
lpFileInfo-> lpNextFileInfo = g_RgFileInfoList;
g_RgFileInfoList = lpFileInfo;
*lplpFileInfo = lpFileInfo;
return ERROR_SUCCESS;
ErrorDeleteFile:
if (!(Flags & CFIN_VOLATILE))
RgDeleteFile(lpFileName);
ErrorDestroyFileInfo:
RgDestroyFileInfo(lpFileInfo);
ErrorReturn:
TRACE(("RgCreateFileInfoNew: returning %d\n", ErrorCode));
return ErrorCode;
}
//
// RgCreateFileInfoExisting
//
int
INTERNAL
RgCreateFileInfoExisting(
LPFILE_INFO FAR* lplpFileInfo,
LPCSTR lpFileName
)
{
int ErrorCode;
LPFILE_INFO lpFileInfo;
HFILE hFile;
DWORD FileAttributes;
if (IsNullPtr((lpFileInfo = (LPFILE_INFO)
RgSmAllocMemory(sizeof(FILE_INFO) + StrLen(lpFileName))))) {
ErrorCode = ERROR_OUTOFMEMORY;
goto ErrorReturn;
}
ZeroMemory(lpFileInfo, sizeof(FILE_INFO));
StrCpy(lpFileInfo-> FileName, lpFileName);
// lpFileInfo-> Flags = 0;
// lpFileInfo-> lpHiveInfoList = NULL;
// lpFileInfo-> lpParentFileInfo = NULL;
// lpFileInfo-> lpNotifyChangeList = NULL;
// lpFileInfo-> lpKeynodeBlockInfo = NULL;
// lpFileInfo-> NumKeynodeBlocks = 0;
// lpFileInfo-> NumAllocKNBlocks = 0;
// lpFileInfo-> CurTotalKnSize = 0;
// lpFileInfo-> lpDatablockInfo = NULL;
// lpFileInfo-> DatablockInfoAllocCount = 0;
ErrorCode = ERROR_REGISTRY_IO_FAILED; // Assume this error code
// Attempt to the open the given filename.
if ((hFile = RgOpenFile(lpFileName, OF_READ)) == HFILE_ERROR)
goto ErrorDestroyFileInfo;
// Read and validate the file header.
if (!RgReadFile(hFile, &lpFileInfo-> FileHeader, sizeof(FILE_HEADER)))
goto ErrorCloseFile;
if (lpFileInfo-> FileHeader.Signature != FH_SIGNATURE ||
(lpFileInfo-> FileHeader.Version != FH_VERSION10 &&
lpFileInfo-> FileHeader.Version != FH_VERSION20)) {
ErrorCode = ERROR_BADDB;
goto ErrorCloseFile;
}
lpFileInfo-> FileHeader.Flags &= ~(FHF_DIRTY | FHF_HASCHECKSUM);
if (lpFileInfo-> FileHeader.Version == FH_VERSION20)
lpFileInfo-> Flags |= FI_VERSION20;
// Read and validate the keynode header.
if (!RgReadFile(hFile, &lpFileInfo-> KeynodeHeader,
sizeof(KEYNODE_HEADER)))
goto ErrorCloseFile;
if (lpFileInfo-> KeynodeHeader.Signature != KH_SIGNATURE) {
ErrorCode = ERROR_BADDB;
goto ErrorCloseFile;
}
// Init the keynode data structures.
if ((ErrorCode = RgInitKeynodeInfo(lpFileInfo)) != ERROR_SUCCESS)
goto ErrorCloseFile;
// Init the datablock data structures.
if ((ErrorCode = RgInitDatablockInfo(lpFileInfo, hFile)) != ERROR_SUCCESS)
goto ErrorCloseFile;
RgCloseFile(hFile);
// Check if the file can be written to. We did this in Win95 by getting
// the current file attributes and then slamming them back on the file. If
// this failed, then we treated the file as read-only (such as hive from
// a read-only network share). This seems to work, so why change?
if ((FileAttributes = RgGetFileAttributes(lpFileName)) != (DWORD) -1) {
if (!RgSetFileAttributes(lpFileName, (UINT) FileAttributes))
lpFileInfo-> Flags |= FI_READONLY;
}
// Link this FILE_INFO into the global file info list.
lpFileInfo-> lpNextFileInfo = g_RgFileInfoList;
g_RgFileInfoList = lpFileInfo;
*lplpFileInfo = lpFileInfo;
return ERROR_SUCCESS;
ErrorCloseFile:
RgCloseFile(hFile);
ErrorDestroyFileInfo:
RgDestroyFileInfo(lpFileInfo);
ErrorReturn:
TRACE(("RgCreateFileInfoExisting: returning %d\n", ErrorCode));
return ErrorCode;
}
//
// RgDestroyFileInfo
//
// Unlinks the FILE_INFO from the global list, if appropriate, and frees all
// memory associated with the structure including the structure itself.
//
// If the FILE_INFO is dirty, then all changes will be lost. Call
// RgFlushFileInfo first if the file should be flushed.
//
int
INTERNAL
RgDestroyFileInfo(
LPFILE_INFO lpFileInfo
)
{
LPFILE_INFO lpPrevFileInfo;
LPFILE_INFO lpCurrFileInfo;
#ifdef WANT_HIVE_SUPPORT
LPHIVE_INFO lpHiveInfo;
LPHIVE_INFO lpTempHiveInfo;
#endif
#ifdef WANT_NOTIFY_CHANGE_SUPPORT
LPNOTIFY_CHANGE lpNotifyChange;
LPNOTIFY_CHANGE lpTempNotifyChange;
#endif
UINT Counter;
LPKEYNODE_BLOCK_INFO lpKeynodeBlockInfo;
LPDATABLOCK_INFO lpDatablockInfo;
ASSERT(!IsNullPtr(lpFileInfo));
RgInvalidateKeyHandles(lpFileInfo, (UINT) -1);
//
// Unlink this FILE_INFO from the the file info list. Note that the
// structure may not have actually been linked in if we're called as a
// result of an error in one of the create file info functions.
//
lpPrevFileInfo = NULL;
lpCurrFileInfo = g_RgFileInfoList;
while (!IsNullPtr(lpCurrFileInfo)) {
if (lpCurrFileInfo == lpFileInfo) {
if (IsNullPtr(lpPrevFileInfo))
g_RgFileInfoList = lpCurrFileInfo-> lpNextFileInfo;
else
lpPrevFileInfo-> lpNextFileInfo = lpCurrFileInfo->
lpNextFileInfo;
break;
}
lpPrevFileInfo = lpCurrFileInfo;
lpCurrFileInfo = lpCurrFileInfo-> lpNextFileInfo;
}
#ifdef WANT_HIVE_SUPPORT
//
// Delete all of the hives connected to this FILE_INFO.
//
lpHiveInfo = lpFileInfo-> lpHiveInfoList;
while (!IsNullPtr(lpHiveInfo)) {
RgDestroyFileInfo(lpHiveInfo-> lpFileInfo);
lpTempHiveInfo = lpHiveInfo;
lpHiveInfo = lpHiveInfo-> lpNextHiveInfo;
RgSmFreeMemory(lpTempHiveInfo);
}
#endif
#ifdef WANT_NOTIFY_CHANGE_SUPPORT
//
// Signal and free all of the change notifications. On NT, a hive cannot
// be unloaded if there are any open handles referencing it. Change
// notifications are cleaned up when a key handle is closed. So this
// cleanup is unique to our registry code.
//
lpNotifyChange = lpFileInfo-> lpNotifyChangeList;
while (!IsNullPtr(lpNotifyChange)) {
RgSetAndReleaseEvent(lpNotifyChange-> hEvent);
lpTempNotifyChange = lpNotifyChange;
lpNotifyChange = lpNotifyChange-> lpNextNotifyChange;
RgSmFreeMemory(lpTempNotifyChange);
}
#endif
//
// Free all memory associated with the keynode table.
//
if (!IsNullPtr(lpFileInfo-> lpKeynodeBlockInfo)) {
for (Counter = 0, lpKeynodeBlockInfo = lpFileInfo-> lpKeynodeBlockInfo;
Counter < lpFileInfo-> KeynodeBlockCount; Counter++,
lpKeynodeBlockInfo++) {
if (!IsNullPtr(lpKeynodeBlockInfo-> lpKeynodeBlock))
RgFreeMemory(lpKeynodeBlockInfo-> lpKeynodeBlock);
}
RgSmFreeMemory(lpFileInfo-> lpKeynodeBlockInfo);
}
//
// Free all memory associated with the datablocks.
//
if (!IsNullPtr(lpFileInfo-> lpDatablockInfo)) {
for (Counter = 0, lpDatablockInfo = lpFileInfo-> lpDatablockInfo;
Counter < lpFileInfo-> FileHeader.BlockCount; Counter++,
lpDatablockInfo++)
RgFreeDatablockInfoBuffers(lpDatablockInfo);
RgSmFreeMemory(lpFileInfo-> lpDatablockInfo);
}
//
// Free the FILE_INFO itself.
//
RgSmFreeMemory(lpFileInfo);
return ERROR_SUCCESS;
}
#ifdef VXD
#pragma VxD_PAGEABLE_CODE_SEG
#endif
//
// RgFlushFileInfo
//
int
INTERNAL
RgFlushFileInfo(
LPFILE_INFO lpFileInfo
)
{
int ErrorCode;
HFILE hSourceFile;
HFILE hDestinationFile;
char TempFileName[MAX_PATH];
UINT Index;
ASSERT(!IsNullPtr(lpFileInfo));
if (!IsPostCriticalInit() || IsFileAccessDisabled())
return ERROR_SUCCESS; // Win95 compatibility.
if (!(lpFileInfo-> Flags & FI_DIRTY))
return ERROR_SUCCESS;
// If we're currently flushing this FILE_INFO and are called again because
// of low memory conditions, ignore this request. Or if this is a memory
// only registry file, there's nothing to flush to.
if (lpFileInfo-> Flags & (FI_FLUSHING | FI_VOLATILE))
return ERROR_SUCCESS;
lpFileInfo-> Flags |= FI_FLUSHING;
ErrorCode = ERROR_REGISTRY_IO_FAILED; // Assume this error code
hSourceFile = HFILE_ERROR;
hDestinationFile = HFILE_ERROR;
if (!RgSetFileAttributes(lpFileInfo-> FileName, FILE_ATTRIBUTE_NONE))
goto CleanupAfterError;
// Datablocks really shouldn't need to set this flag-- instead
// do some smart checking to see if we really need to rewrite the whole
// bloody thing.
if (lpFileInfo-> Flags & FI_EXTENDED) {
if ((Index = StrLen(lpFileInfo-> FileName)) >= MAX_PATH)
goto CleanupAfterError;
StrCpy(TempFileName, lpFileInfo-> FileName);
// Back up to the last backslash (or the start of the string) and
// null-terminate.
do {
Index--;
} while (Index > 0 && TempFileName[Index] != '\\');
// If we found a backslash, then null terminate the string after the
// backslash. Otherwise, we don't have a full qualified pathname, so
// make the temporary file in the current directory and pray that's
// where the registry file is.
if (Index != 0)
TempFileName[Index + 1] = '\0';
else
StrCpy(TempFileName, g_RgDotBackslashPath);
if ((hDestinationFile = RgCreateTempFile(TempFileName)) ==
HFILE_ERROR)
goto CleanupAfterError;
if ((hSourceFile = RgOpenFile(lpFileInfo-> FileName, OF_READ)) ==
HFILE_ERROR)
goto CleanupAfterError;
TRACE(("rewriting to TempFileName = \""));
TRACE((TempFileName));
TRACE(("\"\n"));
}
else {
if ((hDestinationFile = RgOpenFile(lpFileInfo-> FileName, OF_WRITE)) ==
HFILE_ERROR)
goto CleanupAfterError;
// Mark the file is in the process of being updated
lpFileInfo-> FileHeader.Flags |= FHF_FILEDIRTY | FHF_DIRTY;
}
// Write out the file header.
if (hSourceFile != HFILE_ERROR || lpFileInfo-> FileHeader.Flags &
FHF_DIRTY) {
lpFileInfo-> FileHeader.Flags |= FHF_SUPPORTSDIRTY;
// Note that RgWriteDatablocks and RgWriteDatablocksComplete uses this
// value, too.
if (lpFileInfo-> Flags & FI_VERSION20)
lpFileInfo-> FileHeader.Size = sizeof(VERSION20_HEADER_PAGE) +
lpFileInfo-> CurTotalKnSize;
else
lpFileInfo-> FileHeader.Size = sizeof(FILE_HEADER) +
lpFileInfo-> CurTotalKnSize;
if (!RgWriteFile(hDestinationFile, &lpFileInfo-> FileHeader,
sizeof(FILE_HEADER)))
goto CleanupAfterError;
// Commit the change to disk, if we are modifying in place
if (lpFileInfo-> FileHeader.Flags & FHF_FILEDIRTY)
{
if (!RgCommitFile(hDestinationFile))
goto CleanupAfterError;
}
}
// Write out the keynode header and table.
if ((ErrorCode = RgWriteKeynodes(lpFileInfo, hSourceFile,
hDestinationFile)) != ERROR_SUCCESS) {
TRACE(("RgWriteKeynodes returned error %d\n", ErrorCode));
goto CleanupAfterError;
}
// Write out the datablocks.
if ((ErrorCode = RgWriteDatablocks(lpFileInfo, hSourceFile,
hDestinationFile)) != ERROR_SUCCESS) {
TRACE(("RgWriteDatablocks returned error %d\n", ErrorCode));
goto CleanupAfterError;
}
// Ensure that the file is actually written
if (!RgCommitFile(hDestinationFile))
goto CleanupAfterError;
// Mark the file update as complete
if (lpFileInfo-> FileHeader.Flags & FHF_FILEDIRTY)
{
lpFileInfo-> FileHeader.Flags &= ~FHF_FILEDIRTY;
if (!RgSeekFile(hDestinationFile, 0))
goto CleanupAfterError;
if (!RgWriteFile(hDestinationFile, &lpFileInfo-> FileHeader,
sizeof(FILE_HEADER)))
goto CleanupAfterError;
}
RgCloseFile(hDestinationFile);
// If we're extending the file, we now go back and delete the current file
// and replace it with our temporary file.
if (hSourceFile != HFILE_ERROR) {
RgCloseFile(hSourceFile);
ErrorCode = ERROR_REGISTRY_IO_FAILED; // Assume this error code
if (!RgDeleteFile(lpFileInfo-> FileName))
goto CleanupAfterFilesClosed;
if (!RgRenameFile(TempFileName, lpFileInfo-> FileName)) {
// If we ever hit this, we're in trouble. Need to handle it
// somehow, though.
DEBUG_OUT(("RgFlushFileInfo failed to replace backing file\n"));
goto CleanupAfterFilesClosed;
}
}
// Go back and tell everyone that the write is complete-- the file has
// been successfully written to disk.
RgWriteDatablocksComplete(lpFileInfo);
RgWriteKeynodesComplete(lpFileInfo);
lpFileInfo-> FileHeader.Flags &= ~FHF_DIRTY;
lpFileInfo-> Flags &= ~(FI_DIRTY | FI_EXTENDED);
ErrorCode = ERROR_SUCCESS;
CleanupAfterFilesClosed:
RgSetFileAttributes(lpFileInfo-> FileName, FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_HIDDEN);
lpFileInfo-> Flags &= ~FI_FLUSHING;
if (ErrorCode != ERROR_SUCCESS)
DEBUG_OUT(("RgFlushFileInfo() returning error %d\n", ErrorCode));
return ErrorCode;
CleanupAfterError:
if (hSourceFile != HFILE_ERROR)
RgCloseFile(hSourceFile);
if (hDestinationFile != HFILE_ERROR) {
// If both hSourceFile and hDestinationFile were valid, then we must
// have created a temporary file. Delete it now that we've failed.
if (hSourceFile != HFILE_ERROR)
RgDeleteFile(TempFileName);
RgSetFileAttributes(lpFileInfo-> FileName, FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_HIDDEN);
}
goto CleanupAfterFilesClosed;
}
//
// RgSweepFileInfo
//
int
INTERNAL
RgSweepFileInfo(
LPFILE_INFO lpFileInfo
)
{
ASSERT(!IsNullPtr(lpFileInfo));
// If we're currently sweeping this FILE_INFO and are called again because
// of low memory conditions, ignore this request. Or if this is a memory
// only registry file, we can't sweep anything out.
if (lpFileInfo-> Flags & (FI_FLUSHING | FI_VOLATILE))
return ERROR_SUCCESS;
lpFileInfo-> Flags |= FI_SWEEPING;
RgSweepKeynodes(lpFileInfo);
RgSweepDatablocks(lpFileInfo);
lpFileInfo-> Flags &= ~FI_SWEEPING;
return ERROR_SUCCESS;
}
//
// RgEnumFileInfos
//
// Enumerates over all FILE_INFO structures, passing each to the provided
// callback. Currently, all errors from callbacks are ignored.
//
VOID
INTERNAL
RgEnumFileInfos(
LPENUMFILEINFOPROC lpEnumFileInfoProc
)
{
LPFILE_INFO lpFileInfo;
LPFILE_INFO lpTempFileInfo;
lpFileInfo = g_RgFileInfoList;
while (!IsNullPtr(lpFileInfo)) {
lpTempFileInfo = lpFileInfo;
lpFileInfo = lpFileInfo-> lpNextFileInfo;
(*lpEnumFileInfoProc)(lpTempFileInfo);
}
}
#ifdef VXD
#pragma VxD_RARE_CODE_SEG
#endif
//
// RgInitRootKeyFromFileInfo
//
// Using the FILE_INFO contained in the key, initialize the rest of the members
// of the key. If any errors occur, then the FILE_INFO is destroyed.
//
int
INTERNAL
RgInitRootKeyFromFileInfo(
HKEY hKey
)
{
int ErrorCode;
LPKEYNODE lpKeynode;
hKey-> KeynodeIndex = hKey-> lpFileInfo-> KeynodeHeader.RootIndex;
if ((ErrorCode = RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
&lpKeynode)) == ERROR_SUCCESS) {
hKey-> Signature = KEY_SIGNATURE;
hKey-> Flags &= ~(KEYF_INVALID | KEYF_DELETED | KEYF_ENUMKEYCACHED);
hKey-> ChildKeynodeIndex = lpKeynode-> ChildIndex;
hKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
hKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, FALSE);
}
else
RgDestroyFileInfo(hKey-> lpFileInfo);
return ErrorCode;
}
#ifdef VXD
#pragma VxD_INIT_CODE_SEG
#endif
//
// VMMRegMapPredefKeyToFile
//
LONG
REGAPI
VMMRegMapPredefKeyToFile(
HKEY hKey,
LPCSTR lpFileName,
UINT Flags
)
{
int ErrorCode;
#ifdef WIN32
char FullPathName[MAX_PATH];
#endif
UINT CreateNewFlags;
if (hKey != HKEY_LOCAL_MACHINE && hKey != HKEY_USERS
#ifndef VXD
&& hKey != HKEY_CURRENT_USER
#endif
)
return ERROR_INVALID_PARAMETER;
if (IsBadOptionalStringPtr(lpFileName, (UINT) -1))
return ERROR_INVALID_PARAMETER;
if (!RgLockRegistry())
return ERROR_LOCK_FAILED;
RgValidateAndConvertKeyHandle(&hKey);
if (!(hKey-> Flags & KEYF_INVALID))
RgDestroyFileInfo(hKey-> lpFileInfo);
// Specifying NULL "unmaps" the key and leaves it invalidated.
if (IsNullPtr(lpFileName))
return ERROR_SUCCESS;
#ifdef WIN32
// For users of the Win32 DLL, resolve the path name so they don't have to.
if ((GetFullPathName(lpFileName, sizeof(FullPathName), FullPathName,
NULL)) != 0)
lpFileName = FullPathName;
#endif
if (Flags & MPKF_CREATENEW) {
CreateNewFlags = CFIN_PRIMARY | ((Flags & MPKF_VERSION20) ?
CFIN_VERSION20 : 0);
ErrorCode = RgCreateFileInfoNew(&hKey-> lpFileInfo, lpFileName,
CreateNewFlags);
}
else {
ErrorCode = RgCreateFileInfoExisting(&hKey-> lpFileInfo, lpFileName);
}
if (ErrorCode == ERROR_SUCCESS)
ErrorCode = RgInitRootKeyFromFileInfo(hKey);
RgUnlockRegistry();
return ErrorCode;
}