|
|
//
// 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;
}
|