You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1317 lines
34 KiB
1317 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
registry.c
|
|
|
|
Abstract:
|
|
|
|
Interfaces for registering and deregistering registry checkpoint
|
|
handlers.
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 1/16/1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "cpp.h"
|
|
|
|
//
|
|
// Local type and structure definitions
|
|
//
|
|
typedef struct _CPP_ADD_CONTEXT {
|
|
BOOL Found;
|
|
LPCWSTR KeyName;
|
|
} CPP_ADD_CONTEXT, *PCPP_ADD_CONTEXT;
|
|
|
|
typedef struct _CPP_DEL_CONTEXT {
|
|
DWORD dwId;
|
|
LPCWSTR KeyName;
|
|
} CPP_DEL_CONTEXT, *PCPP_DEL_CONTEXT;
|
|
|
|
typedef struct _CPP_GET_CONTEXT {
|
|
DWORD Available;
|
|
DWORD Required;
|
|
LPWSTR lpOutput;
|
|
} CPP_GET_CONTEXT, *PCPP_GET_CONTEXT;
|
|
|
|
//
|
|
// Local function prototypes
|
|
//
|
|
BOOL
|
|
CppWatchCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PFM_RESOURCE Resource
|
|
);
|
|
|
|
BOOL
|
|
CppAddCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCPP_ADD_CONTEXT Context
|
|
);
|
|
|
|
BOOL
|
|
CppDeleteCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCPP_DEL_CONTEXT Context
|
|
);
|
|
|
|
BOOL
|
|
CppGetCheckpointsCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCPP_GET_CONTEXT Context
|
|
);
|
|
|
|
|
|
DWORD
|
|
CppWatchRegistry(
|
|
IN PFM_RESOURCE Resource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Restores any registry checkpoints for this resource and begins
|
|
watching the registry for any further modifications.
|
|
|
|
Arguments:
|
|
|
|
Resource - Supplies the resource.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
HDMKEY ResourceKey;
|
|
HDMKEY RegSyncKey;
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
CL_ASSERT(ResourceKey != NULL);
|
|
|
|
//
|
|
// Open up the RegSync key
|
|
//
|
|
RegSyncKey = DmOpenKey(ResourceKey,
|
|
L"RegSync",
|
|
KEY_READ);
|
|
DmCloseKey(ResourceKey);
|
|
if (RegSyncKey != NULL) {
|
|
|
|
DmEnumValues(RegSyncKey,
|
|
CppWatchCallback,
|
|
Resource);
|
|
DmCloseKey(RegSyncKey);
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CppWatchCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PFM_RESOURCE Resource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Value enumeration callback for watching a resource's registry
|
|
checkpoint subtrees.
|
|
|
|
Arguments:
|
|
|
|
ValueName - Supplies the name of the value (this is the checkpoint ID)
|
|
|
|
ValueData - Supplies the value data (this is the registry subtree)
|
|
|
|
ValueType - Supplies the value type (must be REG_SZ)
|
|
|
|
ValueSize - Supplies the size of ValueData
|
|
|
|
Resource - Supplies the resource this value is a registry checkpoint for
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hKey;
|
|
DWORD Id;
|
|
DWORD Status;
|
|
DWORD Disposition;
|
|
WCHAR TempFile[MAX_PATH];
|
|
BOOLEAN WasEnabled;
|
|
|
|
Id = wcstol(ValueName, NULL, 16);
|
|
if (Id == 0) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CppWatchCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
|
|
ValueName,
|
|
OmObjectName(Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Attempt to create the specified registry key.
|
|
//
|
|
Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
ValueData,
|
|
0,
|
|
NULL,
|
|
0,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
if (Status != ERROR_SUCCESS) {
|
|
//
|
|
// For some reason we could not open the key. Try again with restore
|
|
// privilege. Note that this will not work if the key does not exist.
|
|
// Not much we can do in that case.
|
|
//
|
|
Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
|
|
&WasEnabled);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppWatchCallback - ClRtlEnableThreadPrivilege failed with Status %1!u!\n",
|
|
Status);
|
|
return(TRUE);
|
|
}
|
|
|
|
Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
ValueData,
|
|
REG_OPTION_BACKUP_RESTORE,
|
|
KEY_WRITE,
|
|
&hKey);
|
|
ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
|
|
WasEnabled);
|
|
|
|
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppWatchCallback: could not create key %1!ws! error %2!d!\n",
|
|
ValueData,
|
|
Status);
|
|
return(TRUE);
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CppWatchCallback retrieving checkpoint id %1!lx! for resource %2!ws\n",
|
|
Id,
|
|
OmObjectName(Resource));
|
|
//
|
|
// See if there is any checkpoint data for this ID.
|
|
//
|
|
Status = DmCreateTempFileName(TempFile);
|
|
if (Status != ERROR_SUCCESS) {
|
|
CL_UNEXPECTED_ERROR( Status );
|
|
}
|
|
Status = CpGetDataFile(Resource,
|
|
Id,
|
|
TempFile,
|
|
FALSE);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CppWatchCallback - CpGetDataFile for id %1!lx! resource %2!ws! failed %3!d!\n",
|
|
Id,
|
|
OmObjectName(Resource),
|
|
Status);
|
|
} else {
|
|
|
|
//
|
|
// Finally install the checkpointed file into the registry.
|
|
//
|
|
Status = CppInstallDatabase(hKey,
|
|
TempFile);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppWatchCallback: could not restore temp file %1!ws! to key %2!ws! error %3!d!\n",
|
|
TempFile,
|
|
ValueData,
|
|
Status);
|
|
CsLogEventData2(LOG_CRITICAL,
|
|
CP_REG_CKPT_RESTORE_FAILED,
|
|
sizeof(Status),
|
|
&Status,
|
|
OmObjectName(Resource),
|
|
ValueData);
|
|
}
|
|
|
|
}
|
|
QfsDeleteFile(TempFile);
|
|
RegCloseKey(hKey);
|
|
|
|
//
|
|
// Install the registry watcher for this checkpoint
|
|
//
|
|
Status = CppRegisterNotify(Resource,
|
|
ValueData,
|
|
Id);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppWatchRegistry - CppRegisterNotify failed for key %1!ws! %1!d!\n",
|
|
ValueData,
|
|
Status);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpAddRegistryCheckpoint(
|
|
IN PFM_RESOURCE Resource,
|
|
IN LPCWSTR KeyName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a new registry checkpoint to a resource's list.
|
|
|
|
Arguments:
|
|
|
|
Resource - supplies the resource the registry checkpoint should be added to.
|
|
|
|
KeyName - Supplies the name of the registry key (relative to HKEY_LOCAL_MACHINE);
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
CPP_ADD_CONTEXT Context;
|
|
HDMKEY ResourceKey = NULL;
|
|
HDMKEY RegSyncKey = NULL;
|
|
DWORD Disposition;
|
|
DWORD Id;
|
|
WCHAR IdName[9];
|
|
DWORD Status;
|
|
HKEY hKey = NULL;
|
|
CLUSTER_RESOURCE_STATE State;
|
|
BOOLEAN WasEnabled;
|
|
DWORD Count=60;
|
|
HKEY hKeyOpen = NULL;
|
|
|
|
|
|
//
|
|
// Reject all callers that believe they can checkpoint the Cluster hive or anything under it.
|
|
//
|
|
if ( _wcsnicmp( KeyName, CLUSREG_KEYNAME_CLUSTER, RTL_NUMBER_OF ( CLUSREG_KEYNAME_CLUSTER ) - 1 ) == 0 )
|
|
{
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CpAddRegistryCheckpoint: Invalid key name %1!ws! supplied for resource %2!ws!, status %3!u!\n",
|
|
KeyName,
|
|
OmObjectName(Resource),
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Make sure the specified key is valid.
|
|
// - First we try and open the key while using backup privilege.
|
|
// If the key exists, this will get us a handle even if our account
|
|
// does not have permission.
|
|
// - If you are using REG_OPTION_BACKUP_RESTORE and the key does not
|
|
// exist, a new key will not be created. So if the first create fails,
|
|
// we try again without REG_OPTION_BACKUP_RESTORE. This will create
|
|
// the key if it does not exist (and we have permission to create such
|
|
// a key) If the key does not exist and we cannot create they key,
|
|
// the checkpoint add fails.
|
|
//
|
|
Status = ClRtlEnableThreadPrivilege(SE_BACKUP_PRIVILEGE,
|
|
&WasEnabled);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint - ClRtlEnableThreadPrivilege failed with Status %1!u!\n",
|
|
Status);
|
|
goto FnExit;
|
|
|
|
}
|
|
Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
KeyName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_BACKUP_RESTORE,
|
|
KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
ClRtlRestoreThreadPrivilege(SE_BACKUP_PRIVILEGE,
|
|
WasEnabled);
|
|
if (Status != ERROR_SUCCESS) {
|
|
//
|
|
// Try again without REG_OPTION_BACKUP_RESTORE.
|
|
//
|
|
Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
KeyName,
|
|
0,
|
|
NULL,
|
|
0,
|
|
KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint Could not create key %1!ws! error %2!d!\n",
|
|
KeyName,
|
|
Status);
|
|
goto FnExit;
|
|
} else {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CpAddRegistryCheckpoint created new key %1!ws! for checkpointing.\n",
|
|
KeyName);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 2/26/99
|
|
//
|
|
// Make sure the key can be opened. Else, bail out.
|
|
//
|
|
Status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
|
|
KeyName,
|
|
&hKeyOpen);
|
|
|
|
if ( Status != ERROR_SUCCESS ) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint Could not open key %1!ws! error %2!d!\n",
|
|
KeyName,
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( hKeyOpen != NULL ) {
|
|
RegCloseKey( hKeyOpen );
|
|
}
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
|
|
if( ResourceKey == NULL ) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint couldn't open Resource key for %1!ws! error %2!d!\n",
|
|
OmObjectName(Resource),
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Open up the RegSync key
|
|
//
|
|
RegSyncKey = DmCreateKey(ResourceKey,
|
|
L"RegSync",
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&Disposition);
|
|
DmCloseKey(ResourceKey);
|
|
if (RegSyncKey == NULL) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint couldn't create RegSync key for %1!ws! error %2!d!\n",
|
|
OmObjectName(Resource),
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
if (Disposition == REG_OPENED_EXISTING_KEY) {
|
|
//
|
|
// Enumerate all the other values to make sure this key is
|
|
// not already registered.
|
|
//
|
|
Context.Found = FALSE;
|
|
Context.KeyName = KeyName;
|
|
DmEnumValues(RegSyncKey,
|
|
CppAddCheckpointCallback,
|
|
&Context);
|
|
if (Context.Found) {
|
|
//
|
|
// This checkpoint already exists.
|
|
//
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CpAddRegistryCheckpoint failing attempt to add duplicate checkpoint for %1!ws!\n",
|
|
KeyName);
|
|
Status = ERROR_ALREADY_EXISTS;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Now we need to find a unique checkpoint ID for this registry subtree.
|
|
// Start at 1 and keep trying value names until we get to one that does
|
|
// not already exist.
|
|
//
|
|
for (Id=1; ; Id++) {
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
|
|
wsprintfW(IdName,L"%08lx",Id);
|
|
cbData = 0;
|
|
Status = DmQueryValue(RegSyncKey,
|
|
IdName,
|
|
&dwType,
|
|
NULL,
|
|
&cbData);
|
|
if (Status == ERROR_FILE_NOT_FOUND) {
|
|
//
|
|
// Found a free ID.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// The key was just created, so this must be the only checkpoint
|
|
// that exists.
|
|
//
|
|
Id = 1;
|
|
wsprintfW(IdName, L"%08lx",Id);
|
|
}
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CpAddRegistryCheckpoint creating new checkpoint id %1!d! for subtree %2!ws!\n",
|
|
Id,
|
|
KeyName);
|
|
|
|
Status = DmSetValue(RegSyncKey,
|
|
IdName,
|
|
REG_SZ,
|
|
(CONST BYTE *)KeyName,
|
|
(lstrlenW(KeyName)+1)*sizeof(WCHAR));
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint failed to create new checkpoint id %1!d! error %2!d!\n",
|
|
Id,
|
|
KeyName);
|
|
goto FnExit;
|
|
}
|
|
|
|
RetryCheckpoint:
|
|
//
|
|
// Take the initial checkpoint
|
|
//
|
|
Status = CppCheckpoint(Resource,
|
|
hKey,
|
|
Id,
|
|
KeyName);
|
|
|
|
//this may fail due to quorum resource being offline
|
|
// we could do one of two things here, wait for quorum resource to
|
|
// come online or retry
|
|
// we retry as this may be called from the online routines of a
|
|
//resource and we dont want to add any circular waits
|
|
if ((Status == ERROR_ACCESS_DENIED) ||
|
|
(Status == ERROR_INVALID_FUNCTION) ||
|
|
(Status == ERROR_NOT_READY) ||
|
|
(Status == RPC_X_INVALID_PIPE_OPERATION) ||
|
|
(Status == ERROR_BUSY) ||
|
|
(Status == ERROR_SWAPERROR))
|
|
{
|
|
if (Count--)
|
|
{
|
|
Sleep(1000);
|
|
goto RetryCheckpoint;
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
if (IsDebuggerPresent())
|
|
DebugBreak();
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint failed to take initial checkpoint for %1!ws! error %2!d!\n",
|
|
KeyName,
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// If the resource is currently online, add this to the list of subtree notifications
|
|
//
|
|
|
|
State = FmGetResourceState(Resource, NULL, NULL);
|
|
if ((State == ClusterResourceOnline) ||
|
|
(State == ClusterResourceOnlinePending)) {
|
|
Status = CppRegisterNotify(Resource,
|
|
KeyName,
|
|
Id);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpAddRegistryCheckpoint - CppRegisterNotify failed for key %1!ws! %1!d!\n",
|
|
KeyName,
|
|
Status);
|
|
}
|
|
}
|
|
|
|
FnExit:
|
|
if (RegSyncKey) DmCloseKey(RegSyncKey);
|
|
if (hKey) RegCloseKey(hKey);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CppAddCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCPP_ADD_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Value enumeration callback for adding a new registry
|
|
checkpoint subtrees. This is only used to see if the specified
|
|
registry subtree is already being watched.
|
|
|
|
Arguments:
|
|
|
|
ValueName - Supplies the name of the value (this is the checkpoint ID)
|
|
|
|
ValueData - Supplies the value data (this is the registry subtree)
|
|
|
|
ValueType - Supplies the value type (must be REG_SZ)
|
|
|
|
ValueSize - Supplies the size of ValueData
|
|
|
|
Context - Supplies the callback context
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
FALSE if a match is found and enumeration should be stopped
|
|
|
|
--*/
|
|
|
|
{
|
|
if (lstrcmpiW(ValueData, Context->KeyName) == 0) {
|
|
//
|
|
// Found a match
|
|
//
|
|
Context->Found = TRUE;
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpDeleteRegistryCheckpoint(
|
|
IN PFM_RESOURCE Resource,
|
|
IN LPCWSTR KeyName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a registry checkpoint from a resource's list.
|
|
|
|
Arguments:
|
|
|
|
Resource - supplies the resource the registry checkpoint should be added to.
|
|
|
|
KeyName - Supplies the name of the registry key (relative to HKEY_LOCAL_MACHINE);
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
CPP_DEL_CONTEXT Context;
|
|
HDMKEY ResourceKey;
|
|
HDMKEY RegSyncKey;
|
|
DWORD Status;
|
|
WCHAR ValueId[9];
|
|
LPWSTR pszFileName=NULL;
|
|
LPWSTR pszDirectoryName=NULL;
|
|
CLUSTER_RESOURCE_STATE State;
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
CL_ASSERT(ResourceKey != NULL);
|
|
|
|
//
|
|
// Open up the RegSync key
|
|
//
|
|
RegSyncKey = DmOpenKey(ResourceKey,
|
|
L"RegSync",
|
|
KEY_READ | KEY_WRITE);
|
|
DmCloseKey(ResourceKey);
|
|
if (RegSyncKey == NULL) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CpDeleteRegistryCheckpoint - couldn't open RegSync key error %1!d!\n",
|
|
Status);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Enumerate all the values to find this one
|
|
//
|
|
Context.dwId = 0;
|
|
Context.KeyName = KeyName;
|
|
DmEnumValues(RegSyncKey,
|
|
CppDeleteCheckpointCallback,
|
|
&Context);
|
|
if (Context.dwId == 0) {
|
|
//
|
|
// The specified tree was not found.
|
|
//
|
|
DmCloseKey(RegSyncKey);
|
|
return(ERROR_FILE_NOT_FOUND);
|
|
}
|
|
|
|
wsprintfW(ValueId,L"%08lx",Context.dwId);
|
|
Status = DmDeleteValue(RegSyncKey, ValueId);
|
|
DmCloseKey(RegSyncKey);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpDeleteRegistryCheckpoint - couldn't delete value %1!ws! error %2!d!\n",
|
|
ValueId,
|
|
Status);
|
|
return(Status);
|
|
}
|
|
|
|
//delete the file corresponding to this checkpoint
|
|
Status = CpDeleteCheckpointFile(Resource, Context.dwId, NULL);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpDeleteRegistryCheckpoint - couldn't delete checkpoint file , error %1!d!\n",
|
|
Status);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Now remove the checkpoint from our watcher list
|
|
//
|
|
State = FmGetResourceState(Resource, NULL, NULL);
|
|
if ((State == ClusterResourceOnline) ||
|
|
(State == ClusterResourceOnlinePending)) {
|
|
Status = CppRundownCheckpointById(Resource, Context.dwId);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpRemoveResourceCheckpoints(
|
|
IN PFM_RESOURCE Resource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when a resource is deleted to remove all the checkpoints
|
|
and the related stuff in the registry.
|
|
|
|
Arguments:
|
|
|
|
Resource - supplies the resource the registry checkpoint should be added to.
|
|
|
|
KeyName - Supplies the name of the registry key (relative to HKEY_LOCAL_MACHINE);
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
|
|
//delete all the checkpoints corresponding to this resource
|
|
Status = CpDeleteCheckpointFile(Resource, 0, NULL);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpRemoveResourceCheckpoints, CppDeleteCheckpointFile failed %1!d!\n",
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
|
|
FnExit:
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CppDeleteCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCPP_DEL_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Value enumeration callback for deleting an old registry
|
|
checkpoint subtrees.
|
|
|
|
Arguments:
|
|
|
|
ValueName - Supplies the name of the value (this is the checkpoint ID)
|
|
|
|
ValueData - Supplies the value data (this is the registry subtree)
|
|
|
|
ValueType - Supplies the value type (must be REG_SZ)
|
|
|
|
ValueSize - Supplies the size of ValueData
|
|
|
|
Context - Supplies the callback context
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
FALSE if a match is found and enumeration should be stopped
|
|
|
|
--*/
|
|
|
|
{
|
|
if (lstrcmpiW(ValueData, Context->KeyName) == 0) {
|
|
//
|
|
// Found a match
|
|
//
|
|
Context->dwId = wcstol(ValueName, NULL, 16);
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpGetRegistryCheckpoints(
|
|
IN PFM_RESOURCE Resource,
|
|
OUT PUCHAR OutBuffer,
|
|
IN DWORD OutBufferSize,
|
|
OUT LPDWORD BytesReturned,
|
|
OUT LPDWORD Required
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a list of the resource's registry checkpoints
|
|
|
|
Arguments:
|
|
|
|
Resource - Supplies the resource whose registry checkpoints should be retrieved.
|
|
|
|
OutBuffer - Supplies a pointer to the output buffer.
|
|
|
|
OutBufferSize - Supplies the size (in bytes) of the output buffer.
|
|
|
|
BytesReturned - Returns the number of bytes written to the output buffer.
|
|
|
|
Required - Returns the number of bytes required. (if the output buffer was insufficient)
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
CPP_GET_CONTEXT Context;
|
|
HDMKEY ResourceKey;
|
|
HDMKEY RegSyncKey;
|
|
DWORD Status;
|
|
|
|
*BytesReturned = 0;
|
|
*Required = 0;
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
CL_ASSERT(ResourceKey != NULL);
|
|
|
|
//
|
|
// Open up the RegSync key
|
|
//
|
|
RegSyncKey = DmOpenKey(ResourceKey,
|
|
L"RegSync",
|
|
KEY_READ | KEY_WRITE);
|
|
DmCloseKey(ResourceKey);
|
|
if (RegSyncKey == NULL) {
|
|
//
|
|
// No reg sync key, therefore there are no subtrees
|
|
//
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
Context.Available = OutBufferSize;
|
|
Context.Required = 0;
|
|
Context.lpOutput = (LPWSTR)OutBuffer;
|
|
|
|
DmEnumValues(RegSyncKey,
|
|
CppGetCheckpointsCallback,
|
|
&Context);
|
|
|
|
DmCloseKey(RegSyncKey);
|
|
|
|
if (Context.Available < sizeof(WCHAR)) {
|
|
Status = ERROR_MORE_DATA;
|
|
} else {
|
|
if ( (PCHAR)(Context.lpOutput) - OutBuffer ) {
|
|
*Context.lpOutput++ = L'\0';
|
|
}
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
if ( Context.Required ) {
|
|
*Required = Context.Required + sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// If the buffer was large enough for all the data, indicate the
|
|
// number of bytes we are returning in the output buffer.
|
|
//
|
|
if ( OutBufferSize >= *Required ) {
|
|
*BytesReturned = (DWORD)((PCHAR)(Context.lpOutput) - OutBuffer);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
BOOL
|
|
CppGetCheckpointsCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCPP_GET_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Value enumeration callback for retrieving all of a resource's
|
|
checkpoint subtrees.
|
|
|
|
Arguments:
|
|
|
|
ValueName - Supplies the name of the value (this is the checkpoint ID)
|
|
|
|
ValueData - Supplies the value data (this is the registry subtree)
|
|
|
|
ValueType - Supplies the value type (must be REG_SZ)
|
|
|
|
ValueSize - Supplies the size of ValueData
|
|
|
|
Context - Supplies the callback context
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
Context->Required += ValueSize;
|
|
if (Context->Available >= ValueSize) {
|
|
CopyMemory(Context->lpOutput, ValueData, ValueSize);
|
|
Context->lpOutput += ValueSize/sizeof(WCHAR);
|
|
Context->Available -= ValueSize;
|
|
} else {
|
|
Context->Available = 0;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
DWORD CppSaveCheckpointToFile(
|
|
IN HKEY hKey,
|
|
IN LPCWSTR KeyName,
|
|
IN LPWSTR TempFile)
|
|
{
|
|
DWORD Status;
|
|
|
|
Status = DmCreateTempFileName(TempFile);
|
|
if (Status != ERROR_SUCCESS) {
|
|
CL_UNEXPECTED_ERROR( Status );
|
|
TempFile[0] = L'\0';
|
|
return(Status);
|
|
}
|
|
|
|
Status = DmGetDatabase(hKey, TempFile);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CppCheckpoint failed to get registry database %1!ws! to file %2!ws! error %3!d!\n",
|
|
KeyName,
|
|
TempFile,
|
|
Status);
|
|
CL_LOGFAILURE(Status);
|
|
QfsDeleteFile(TempFile);
|
|
TempFile[0] = L'\0';
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CppCheckpoint(
|
|
IN PFM_RESOURCE Resource,
|
|
IN HKEY hKey,
|
|
IN DWORD dwId,
|
|
IN LPCWSTR KeyName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a checkpoint of the specified registry key.
|
|
|
|
Arguments:
|
|
|
|
Resource - Supplies the resource this is a checkpoint for.
|
|
|
|
hKey - Supplies the registry subtree to checkpoint
|
|
|
|
dwId - Supplies the checkpoint ID.
|
|
|
|
KeyName - Supplies the name of the registry key.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
WCHAR TempFile[MAX_PATH];
|
|
|
|
Status = CppSaveCheckpointToFile(hKey, KeyName, TempFile);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Got a file with the right bits in it. Checkpoint the
|
|
// file.
|
|
//
|
|
Status = CpSaveDataFile(Resource,
|
|
dwId,
|
|
TempFile,
|
|
FALSE);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCheckpoint - CpSaveData failed %1!d!\n",
|
|
Status);
|
|
}
|
|
}
|
|
//if the file was created, delete it
|
|
if (TempFile[0] != L'\0')
|
|
QfsDeleteFile(TempFile);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CppInstallDatabase(
|
|
IN HKEY hKey,
|
|
IN LPWSTR FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Installs a new registry database from a specified file.
|
|
|
|
Arguments:
|
|
|
|
hKey - Supplies the registry key where FileName will be installed to.
|
|
|
|
FileName - The name of the file from which to read the registry database
|
|
to install.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if the installation completed successfully
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
BOOLEAN WasEnabled;
|
|
|
|
//
|
|
// Install the new registry from the file
|
|
//
|
|
Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
|
|
&WasEnabled);
|
|
if (Status != ERROR_SUCCESS) {
|
|
if (Status == STATUS_PRIVILEGE_NOT_HELD) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] Restore privilege not held by cluster service\n");
|
|
} else {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] Attempt to enable restore privilege failed %1!lx!\n",Status);
|
|
}
|
|
return(Status);
|
|
}
|
|
Status = RegRestoreKeyW(hKey,
|
|
FileName,
|
|
REG_FORCE_RESTORE);
|
|
ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
|
|
WasEnabled);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] Error installing registry database from %1!ws!, error %2!u!.\n",
|
|
FileName,
|
|
Status);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CppDeleteCheckpointFile(
|
|
IN PFM_RESOURCE Resource,
|
|
IN DWORD dwCheckpointId,
|
|
IN OPTIONAL LPCWSTR lpszQuorumPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the checkpoint file corresponding the resource.
|
|
This node must be the owner of the quorum resource
|
|
|
|
Arguments:
|
|
|
|
PFM_RESOURCE - Supplies the pointer to the resource.
|
|
|
|
dwCheckpointId - The checkpoint id to be deleted. If 0, all
|
|
checkpoints are deleted.
|
|
|
|
lpszQuorumPath - If specified, the checkpoint file relative
|
|
to this path is deleted.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if completed successfully
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD Status;
|
|
|
|
|
|
if (dwCheckpointId)
|
|
{
|
|
Status = CppDeleteFile(Resource, dwCheckpointId, lpszQuorumPath);
|
|
}
|
|
else
|
|
{
|
|
HDMKEY ResourceKey;
|
|
HDMKEY RegSyncKey;
|
|
CP_CALLBACK_CONTEXT Context;
|
|
|
|
|
|
//delete all checkpoints corresponding to this resource
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
CL_ASSERT(ResourceKey != NULL);
|
|
|
|
//
|
|
// Open up the RegSync key
|
|
//
|
|
RegSyncKey = DmOpenKey(ResourceKey,
|
|
L"RegSync",
|
|
KEY_READ | KEY_WRITE);
|
|
DmCloseKey(ResourceKey);
|
|
if (RegSyncKey == NULL)
|
|
{
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CppDeleteCheckpointFile- couldn't open RegSync key error %1!d!\n",
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
Context.lpszPathName = lpszQuorumPath;
|
|
Context.Resource = Resource;
|
|
|
|
//
|
|
// Enumerate all the values and delete them one by one.
|
|
//
|
|
DmEnumValues(RegSyncKey,
|
|
CppRemoveCheckpointFileCallback,
|
|
&Context);
|
|
DmCloseKey(RegSyncKey);
|
|
}
|
|
|
|
FnExit:
|
|
return(Status);
|
|
|
|
}
|
|
|
|
DWORD CppDeleteFile(
|
|
IN PFM_RESOURCE Resource,
|
|
IN DWORD dwCheckpointId,
|
|
IN OPTIONAL LPCWSTR lpszQuorumPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the file corresponding to the checkpoint id relative
|
|
to the supplied path and deletes it.
|
|
|
|
Arguments:
|
|
|
|
PFM_RESOURCE - Supplies the pointer to the resource.
|
|
|
|
dwCheckpointId - The checkpoint id to be deleted. If 0, all
|
|
checkpoints are deleted.
|
|
|
|
lpszQuorumPath - If specified, the checkpoint file relative
|
|
to this path is deleted.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if the completed successfully
|
|
|
|
Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
LPWSTR pszFileName=NULL;
|
|
LPWSTR pszDirectoryName=NULL;
|
|
|
|
Status = CppGetCheckpointFile(Resource, dwCheckpointId,
|
|
&pszDirectoryName, &pszFileName, lpszQuorumPath, FALSE);
|
|
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppDeleteFile- couldnt get checkpoint file name, error %1!d!\n",
|
|
Status);
|
|
goto FnExit;
|
|
}
|
|
|
|
|
|
if (!QfsDeleteFile(pszFileName))
|
|
{
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppDeleteFile - couldn't delete the file %2!ws!, error %1!d!\n",
|
|
Status,
|
|
pszFileName);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Now try and delete the directory.
|
|
//
|
|
if (!QfsRemoveDirectory(pszDirectoryName))
|
|
{
|
|
//if there is a failure, we still return success
|
|
//because it may not be possible to delete a directory
|
|
//when it is not empty
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CppDeleteFile- unable to remove directory %1!ws!, error %2!d!\n",
|
|
pszDirectoryName,
|
|
GetLastError());
|
|
}
|
|
|
|
FnExit:
|
|
if (pszFileName) LocalFree(pszFileName);
|
|
if (pszDirectoryName) LocalFree(pszDirectoryName);
|
|
|
|
return(Status);
|
|
}
|
|
|