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.
1018 lines
28 KiB
1018 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cpinit.c
|
|
|
|
Abstract:
|
|
|
|
Initialization and shutdown code for the Checkpoint Manager (CP)
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 1/14/1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "cpp.h"
|
|
|
|
extern PFM_RESOURCE gpQuoResource;
|
|
|
|
BOOL
|
|
CppCopyCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCP_CALLBACK_CONTEXT Context
|
|
);
|
|
|
|
BOOL
|
|
CpckCopyCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCP_CALLBACK_CONTEXT Context
|
|
);
|
|
|
|
BOOL
|
|
CppEnumResourceCallback(
|
|
IN PCP_CALLBACK_CONTEXT pCbContext,
|
|
IN PVOID Context2,
|
|
IN PFM_RESOURCE Resource,
|
|
IN LPCWSTR Name
|
|
);
|
|
|
|
BOOL
|
|
CpckEnumResourceCallback(
|
|
IN PCP_CALLBACK_CONTEXT pCbContext,
|
|
IN PVOID Context2,
|
|
IN PFM_RESOURCE Resource,
|
|
IN LPCWSTR Name
|
|
);
|
|
|
|
|
|
VOID
|
|
CppResourceNotify(
|
|
IN PVOID Context,
|
|
IN PFM_RESOURCE Resource,
|
|
IN DWORD NotifyCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resource notification callback for hooking resource state
|
|
changes. This allows to to register/deregister our registry
|
|
notifications for that resource.
|
|
|
|
Arguments:
|
|
|
|
Context - Supplies the context. Not used
|
|
|
|
Resource - Supplies the resource that is going online or
|
|
has been taken offline.
|
|
|
|
NotifyCode - Supplies the type of notification, either
|
|
NOTIFY_RESOURCE_PREONLINE or NOTIFY_RESOURCE_POSTOFFLINE
|
|
/NOTIFY_RESOURCE_FAILED.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CppResourceNotify for resource %1!ws!\n",
|
|
OmObjectName(Resource));
|
|
|
|
if ( Resource->QuorumResource ) {
|
|
return;
|
|
}
|
|
|
|
if (NotifyCode == NOTIFY_RESOURCE_PREONLINE) {
|
|
//
|
|
// If you are running in fix quorum mode and the quorum resource is offline, then there
|
|
// is really no point attempting to restore the checkpoints since you are doomed to
|
|
// fail accessing the quorum.
|
|
//
|
|
if ( ( CsNoQuorum ) && ( gpQuoResource->State == ClusterResourceOffline ) ) return;
|
|
|
|
//
|
|
// Restore any checkpointed registry state for this resource
|
|
// This will also start the registry notification thread.
|
|
//
|
|
Resource->CheckpointState = 0;
|
|
Status = CppWatchRegistry(Resource);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppWatchRegistry for resource %1!ws! failed %2!d!\n",
|
|
OmObjectName(Resource),
|
|
Status);
|
|
}
|
|
|
|
Status = CpckReplicateCryptoKeys(Resource);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpckReplicateCryptoKeys for resource %1!ws! failed %2!d!\n",
|
|
OmObjectName(Resource),
|
|
Status);
|
|
}
|
|
} else {
|
|
CL_ASSERT(NotifyCode == NOTIFY_RESOURCE_POSTOFFLINE ||
|
|
NotifyCode == NOTIFY_RESOURCE_FAILED);
|
|
//
|
|
// Remove any posted registry notification for this resource
|
|
//
|
|
Status = CppRundownCheckpoints(Resource);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppUnWatchRegistry for resource %1!ws! failed %2!d!\n",
|
|
OmObjectName(Resource),
|
|
Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the checkpoint manager
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
|
|
InitializeCriticalSection(&CppNotifyLock);
|
|
InitializeListHead(&CpNotifyListHead);
|
|
//
|
|
// Register for resource online/offline notifications
|
|
//
|
|
Status = OmRegisterTypeNotify(ObjectTypeResource,
|
|
NULL,
|
|
NOTIFY_RESOURCE_PREONLINE |
|
|
NOTIFY_RESOURCE_POSTOFFLINE|
|
|
NOTIFY_RESOURCE_FAILED,
|
|
CppResourceNotify);
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpShutdown(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Shuts down the Checkpoint Manager
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DeleteCriticalSection(&CppNotifyLock);
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpCompleteQuorumChange(
|
|
IN LPCWSTR lpszOldQuorumPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a change of the quorum disk. This involves deleting
|
|
all the checkpoint files on the old quorum disk.
|
|
|
|
Simple algorithm used here is to enumerate all the resources.
|
|
For each resource, enumerate all its checkpoints and delete the
|
|
checkpoint files.
|
|
|
|
Arguments:
|
|
|
|
lpszNewQuorumPath - Supplies the new quorum path.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
CP_CALLBACK_CONTEXT CbContext;
|
|
|
|
CbContext.lpszPathName = lpszOldQuorumPath;
|
|
|
|
OmEnumObjects(ObjectTypeResource,
|
|
CppEnumResourceCallback,
|
|
(PVOID)&CbContext,
|
|
CppRemoveCheckpointFileCallback);
|
|
|
|
OmEnumObjects(ObjectTypeResource,
|
|
CpckEnumResourceCallback,
|
|
(PVOID)&CbContext,
|
|
CpckRemoveCheckpointFileCallback);
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CpCopyCheckpointFiles(
|
|
IN LPCWSTR lpszPathName,
|
|
IN BOOL IsChangeFileAttribute
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies all the checkpoint files from the quorum disk to the supplied
|
|
directory path. This function is invoked whenever the quorum disk
|
|
changes or when the user wants to make a backup of the cluster DB
|
|
on the quorum disk.
|
|
|
|
Simple algorithm used here is to enumerate all the resources.
|
|
For each resource, enumerate all its checkpoints and copy the
|
|
checkpoint files from the quorum disk to the supplied path.
|
|
|
|
Arguments:
|
|
|
|
lpszPathName - Supplies the destination path name.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
Win32 error code otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
CP_CALLBACK_CONTEXT CbContext;
|
|
|
|
CbContext.lpszPathName = lpszPathName;
|
|
CbContext.IsChangeFileAttribute = IsChangeFileAttribute;
|
|
|
|
OmEnumObjects(ObjectTypeResource,
|
|
CppEnumResourceCallback,
|
|
(PVOID)&CbContext,
|
|
CppCopyCheckpointCallback);
|
|
|
|
OmEnumObjects(ObjectTypeResource,
|
|
CpckEnumResourceCallback,
|
|
(PVOID)&CbContext,
|
|
CpckCopyCheckpointCallback);
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CppEnumResourceCallback(
|
|
IN PCP_CALLBACK_CONTEXT pCbContext,
|
|
IN PENUM_VALUE_CALLBACK lpValueEnumRoutine,
|
|
IN PFM_RESOURCE Resource,
|
|
IN LPCWSTR Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resource enumeration callback for copying or deleting checkpoints
|
|
when the quorum resource changes or when the user is making
|
|
a backup of the cluster DB on the quorum disk.
|
|
|
|
Arguments:
|
|
|
|
lpszPathName - Supplies the new quorum path to be passed to lpValueEnumRoutine.
|
|
|
|
lpValueEnumRoutine - Supplies the value enumeration callback to
|
|
be called if checkpoints exist.
|
|
|
|
Resource - Supplies the resource object.
|
|
|
|
Name - Supplies the resource name
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
HDMKEY ResourceKey;
|
|
HDMKEY RegSyncKey;
|
|
CP_CALLBACK_CONTEXT Context;
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
if (ResourceKey != NULL) {
|
|
|
|
//
|
|
// Open up the RegSync key
|
|
//
|
|
RegSyncKey = DmOpenKey(ResourceKey,
|
|
L"RegSync",
|
|
KEY_READ);
|
|
DmCloseKey(ResourceKey);
|
|
if (RegSyncKey != NULL) {
|
|
|
|
Context.lpszPathName = pCbContext->lpszPathName;
|
|
Context.Resource = Resource;
|
|
Context.IsChangeFileAttribute = pCbContext->IsChangeFileAttribute;
|
|
DmEnumValues(RegSyncKey,
|
|
lpValueEnumRoutine,
|
|
&Context);
|
|
DmCloseKey(RegSyncKey);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CppCopyCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCP_CALLBACK_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Registry value enumeration callback used when the quorum resource
|
|
is changing or when the user is making a backup of the cluster DB
|
|
on the quorum disk. Copies the specified checkpoint file from the
|
|
current quorum directory to the supplied path (in the Context parameter).
|
|
|
|
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 quorum change context (new path and resource)
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR OldCheckpointFile[MAX_PATH+1];
|
|
LPWSTR NewCheckpointDir;
|
|
LPWSTR NewCheckpointFile;
|
|
DWORD Status;
|
|
DWORD Id;
|
|
|
|
Id = wcstol(ValueName, NULL, 16);
|
|
if (Id == 0) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CppCopyCheckpointCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
|
|
ValueName,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get a temporary file name for saving the old checkpoint file
|
|
//
|
|
Status = DmCreateTempFileName(OldCheckpointFile);
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCopyCheckpointCallback - DmCreateTempFileName for old file failed with status %1!d! for resource %2!ws!...\n",
|
|
Status,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get the old checkpoint file from the node hosting the quorum resource
|
|
//
|
|
Status = CpGetDataFile(Context->Resource,
|
|
Id,
|
|
OldCheckpointFile,
|
|
FALSE);
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCopyCheckpointCallback - CpGetDataFile for checkpoint ID %2!d! failed with status %1!d! for resource %3!ws!...\n",
|
|
Status,
|
|
Id,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get the new checkpoint file and directory
|
|
//
|
|
Status = CppGetCheckpointFile(Context->Resource,
|
|
Id,
|
|
&NewCheckpointDir,
|
|
&NewCheckpointFile,
|
|
Context->lpszPathName,
|
|
FALSE);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCopyCheckpointCallback - CppGetCheckpointFile for new file failed %1!d!\n",
|
|
Status);
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// If necessary, try to change the file attributes to NORMAL
|
|
//
|
|
if (Context->IsChangeFileAttribute == TRUE) {
|
|
QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_NORMAL);
|
|
QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_NORMAL);
|
|
}
|
|
|
|
|
|
//
|
|
// Create the new directory.
|
|
//
|
|
if (!QfsCreateDirectory(NewCheckpointDir, NULL)) {
|
|
Status = GetLastError();
|
|
if (Status != ERROR_ALREADY_EXISTS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCopyCheckpointCallback unable to create directory %1!ws!, error %2!d!\n",
|
|
NewCheckpointDir,
|
|
Status);
|
|
LocalFree(NewCheckpointFile);
|
|
LocalFree(NewCheckpointDir);
|
|
return(TRUE);
|
|
}
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Copy the old file to the new file
|
|
//
|
|
if (!QfsClRtlCopyFileAndFlushBuffers(OldCheckpointFile, NewCheckpointFile)) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCopyCheckpointCallback unable to copy file %1!ws! to %2!ws!, error %3!d!\n",
|
|
OldCheckpointFile,
|
|
NewCheckpointFile,
|
|
Status);
|
|
}
|
|
|
|
//
|
|
// If necessary, change the file attributes to READONLY
|
|
//
|
|
if ((Status == ERROR_SUCCESS) && (Context->IsChangeFileAttribute == TRUE)) {
|
|
if (!QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_READONLY)
|
|
||
|
|
!QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_READONLY)) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CppCopyCheckpointCallback unable to change file attributes in %1!ws!, error %2!d!\n",
|
|
NewCheckpointDir,
|
|
Status);
|
|
}
|
|
}
|
|
|
|
LocalFree(NewCheckpointFile);
|
|
LocalFree(NewCheckpointDir);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CppRemoveCheckpointFileCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCP_CALLBACK_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Registry value enumeration callback used when the quorum resource
|
|
is changing. Deletes the specified checkpoint file from the old
|
|
quorum directory.
|
|
|
|
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 quorum change context (old path and resource)
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD Status;
|
|
DWORD Id;
|
|
|
|
Id = wcstol(ValueName, NULL, 16);
|
|
if (Id == 0) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CppRemoveCheckpointFileCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
|
|
ValueName,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
Status = CppDeleteFile(Context->Resource, Id, Context->lpszPathName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
CpckEnumResourceCallback(
|
|
IN PCP_CALLBACK_CONTEXT pCbContext,
|
|
IN PENUM_VALUE_CALLBACK lpValueEnumRoutine,
|
|
IN PFM_RESOURCE Resource,
|
|
IN LPCWSTR Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resource enumeration callback for copying or deleting crypto checkpoints
|
|
when the quorum resource changes or when the user is making
|
|
a backup of the cluster DB on the quorum disk.
|
|
|
|
Arguments:
|
|
|
|
lpszPathName - Supplies the new quorum path to be passed to lpValueEnumRoutine.
|
|
|
|
lpValueEnumRoutine - Supplies the value enumeration callback to
|
|
be called if checkpoints exist.
|
|
|
|
Resource - Supplies the resource object.
|
|
|
|
Name - Supplies the resource name
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Status;
|
|
HDMKEY ResourceKey;
|
|
HDMKEY CryptoSyncKey;
|
|
CP_CALLBACK_CONTEXT Context;
|
|
|
|
//
|
|
// Open up the resource's key
|
|
//
|
|
ResourceKey = DmOpenKey(DmResourcesKey,
|
|
OmObjectId(Resource),
|
|
KEY_READ);
|
|
if (ResourceKey != NULL) {
|
|
|
|
//
|
|
// Open up the CryptoSyncKey key
|
|
//
|
|
CryptoSyncKey = DmOpenKey(ResourceKey,
|
|
L"CryptoSync",
|
|
KEY_READ);
|
|
DmCloseKey(ResourceKey);
|
|
if (CryptoSyncKey != NULL) {
|
|
|
|
Context.lpszPathName = pCbContext->lpszPathName;
|
|
Context.Resource = Resource;
|
|
Context.IsChangeFileAttribute = pCbContext->IsChangeFileAttribute;
|
|
DmEnumValues(CryptoSyncKey,
|
|
lpValueEnumRoutine,
|
|
&Context);
|
|
DmCloseKey(CryptoSyncKey);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CpckCopyCheckpointCallback(
|
|
IN LPWSTR ValueName,
|
|
IN LPVOID ValueData,
|
|
IN DWORD ValueType,
|
|
IN DWORD ValueSize,
|
|
IN PCP_CALLBACK_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Crypto key enumeration callback used when the quorum resource
|
|
is changing or when the user is making a backup of the cluster DB
|
|
on the quorum disk. Copies the specified checkpoint file from the
|
|
current quorum directory to the supplied path (in the Context parameter).
|
|
|
|
Arguments:
|
|
|
|
ValueName - Supplies the name of the value (this is the checkpoint ID)
|
|
|
|
ValueData - Supplies the value data (this is the crypto info)
|
|
|
|
ValueType - Supplies the value type (must be REG_BINARY)
|
|
|
|
ValueSize - Supplies the size of ValueData
|
|
|
|
Context - Supplies the quorum change context (new path and resource)
|
|
|
|
Return Value:
|
|
|
|
TRUE to continue enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR OldCheckpointFile[MAX_PATH+1];
|
|
LPWSTR NewCheckpointDir;
|
|
LPWSTR NewCheckpointFile;
|
|
DWORD Status;
|
|
DWORD Id;
|
|
|
|
Id = wcstol(ValueName, NULL, 16);
|
|
if (Id == 0) {
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CPCK] CpckCopyCheckpointCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
|
|
ValueName,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get a temporary file name for saving the old checkpoint file
|
|
//
|
|
Status = DmCreateTempFileName(OldCheckpointFile);
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpckCopyCheckpointCallback - DmCreateTempFileName for old file failed with status %1!d! for resource %2!ws!...\n",
|
|
Status,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get the old checkpoint file from the node hosting the quorum resource
|
|
//
|
|
Status = CpGetDataFile(Context->Resource,
|
|
Id,
|
|
OldCheckpointFile,
|
|
TRUE);
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpckCopyCheckpointCallback - CpGetDataFile for checkpoint ID %2!d! failed with status %1!d! for resource %3!ws!...\n",
|
|
Status,
|
|
Id,
|
|
OmObjectName(Context->Resource));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Get the new checkpoint file and directory
|
|
//
|
|
Status = CppGetCheckpointFile(Context->Resource,
|
|
Id,
|
|
&NewCheckpointDir,
|
|
&NewCheckpointFile,
|
|
Context->lpszPathName,
|
|
TRUE);
|
|
if (Status != ERROR_SUCCESS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CPCK] CpckCopyCheckpointCallback - CppGetCheckpointFile for new file failed %1!d!\n",
|
|
Status);
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// If necessary, try to change the file attributes to NORMAL
|
|
//
|
|
if (Context->IsChangeFileAttribute == TRUE) {
|
|
QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_NORMAL);
|
|
QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_NORMAL);
|
|
}
|
|
|
|
|
|
//
|
|
// Create the new directory.
|
|
//
|
|
if (!QfsCreateDirectory(NewCheckpointDir, NULL)) {
|
|
Status = GetLastError();
|
|
if (Status != ERROR_ALREADY_EXISTS) {
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CPCK] CpckCopyCheckpointCallback unable to create directory %1!ws!, error %2!d!\n",
|
|
NewCheckpointDir,
|
|
Status);
|
|
LocalFree(NewCheckpointFile);
|
|
LocalFree(NewCheckpointDir);
|
|
return(TRUE);
|
|
}
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Copy the old file to the new file
|
|
//
|
|
if (!QfsClRtlCopyFileAndFlushBuffers(OldCheckpointFile, NewCheckpointFile)) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CPCK] CpckCopyCheckpointCallback unable to copy file %1!ws! to %2!ws!, error %3!d!\n",
|
|
OldCheckpointFile,
|
|
NewCheckpointFile,
|
|
Status);
|
|
}
|
|
|
|
//
|
|
// If necessary, change the file attributes to READONLY
|
|
//
|
|
if ((Status == ERROR_SUCCESS) && (Context->IsChangeFileAttribute == TRUE)) {
|
|
if (!QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_READONLY)
|
|
||
|
|
!QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_READONLY)) {
|
|
Status = GetLastError();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CPCK] CpckCopyCheckpointCallback unable to change file attributes in %1!ws!, error %2!d!\n",
|
|
NewCheckpointDir,
|
|
Status);
|
|
}
|
|
}
|
|
|
|
LocalFree(NewCheckpointFile);
|
|
LocalFree(NewCheckpointDir);
|
|
return(TRUE);
|
|
}
|
|
|
|
/****
|
|
@func DWORD | CpRestoreCheckpointFiles | Create a directory if necessary
|
|
and copy all the resource checkpoint files from the backup
|
|
directory to the quorum disk
|
|
|
|
@parm IN LPWSTR | lpszSourcePathName | The name of the source path
|
|
where the files are backed up.
|
|
|
|
@parm IN LPWSTR | lpszSubDirName | The name of the sub-directory under
|
|
the source path which can be a possible candidate for
|
|
containing the resource checkpoint files.
|
|
|
|
@parm IN LPCWSTR | lpszQuoLogPathName | The name of the quorum disk
|
|
path where the files will be restored.
|
|
|
|
@rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
|
|
|
|
@xref <f DmpRestoreClusterDatabase>
|
|
****/
|
|
DWORD CpRestoreCheckpointFiles(
|
|
IN LPWSTR lpszSourcePathName,
|
|
IN LPWSTR lpszSubDirName,
|
|
IN LPCWSTR lpszQuoLogPathName )
|
|
{
|
|
LPWSTR szSourcePathName = NULL;
|
|
LPWSTR szSourceFileName = NULL;
|
|
WCHAR szDestPathName[MAX_PATH];
|
|
WCHAR szDestFileName[MAX_PATH];
|
|
DWORD dwLen;
|
|
QfsHANDLE hFindFile = QfsINVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA FindData;
|
|
WCHAR szTempCpFileNameExtn[10];
|
|
DWORD status;
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 10/20/98
|
|
//
|
|
|
|
dwLen = lstrlenW( lpszSourcePathName );
|
|
dwLen += lstrlenW( lpszSubDirName );
|
|
//
|
|
// It is safer to use dynamic memory allocation for user-supplied
|
|
// path since we don't want to put restrictions on the user
|
|
// on the length of the path that can be supplied. However, as
|
|
// far as our own quorum disk path is concerned, it is system-dependent
|
|
// and static memory allocation for that would suffice.
|
|
//
|
|
szSourcePathName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
|
|
( dwLen + 15 ) *
|
|
sizeof ( WCHAR ) );
|
|
|
|
if ( szSourcePathName == NULL )
|
|
{
|
|
status = GetLastError();
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CpRestoreCheckpointFiles: Error %1!d! in allocating memory for %2!ws! !!!\n",
|
|
status,
|
|
lpszSourcePathName);
|
|
CL_LOGFAILURE( status );
|
|
goto FnExit;
|
|
}
|
|
|
|
lstrcpyW( szSourcePathName, lpszSourcePathName );
|
|
lstrcatW( szSourcePathName, lpszSubDirName );
|
|
|
|
if ( szSourcePathName[dwLen-1] != L'\\' )
|
|
{
|
|
szSourcePathName[dwLen++] = L'\\';
|
|
szSourcePathName[dwLen] = L'\0';
|
|
}
|
|
|
|
mbstowcs ( szTempCpFileNameExtn, "*.CP*", 6 );
|
|
lstrcatW ( szSourcePathName, szTempCpFileNameExtn );
|
|
|
|
//
|
|
// Try to find the first file in the directory
|
|
//
|
|
hFindFile = QfsFindFirstFile( szSourcePathName, &FindData );
|
|
//
|
|
// Reuse the source path name variable
|
|
//
|
|
szSourcePathName[dwLen] = L'\0';
|
|
if ( !QfsIsHandleValid( hFindFile ) )
|
|
{
|
|
status = GetLastError();
|
|
if ( status != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CpRestoreCheckpointFiles: No file can be found in the supplied path %1!ws! Error = %2!%d! !!!\n",
|
|
szSourcePathName,
|
|
status);
|
|
CL_LOGFAILURE( status );
|
|
} else
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
goto FnExit;
|
|
}
|
|
|
|
dwLen = lstrlenW( szSourcePathName );
|
|
|
|
szSourceFileName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
|
|
( dwLen + 1 + LOG_MAX_FILENAME_LENGTH ) *
|
|
sizeof ( WCHAR ) );
|
|
|
|
if ( szSourceFileName == NULL )
|
|
{
|
|
status = GetLastError();
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[CP] CpRestoreCheckpointFiles: Error %1!d! in allocating memory for %2!ws! !!!\n",
|
|
status,
|
|
szSourcePathName);
|
|
CL_LOGFAILURE( status );
|
|
goto FnExit;
|
|
}
|
|
|
|
lstrcpyW( szDestPathName, lpszQuoLogPathName );
|
|
lstrcatW( szDestPathName, lpszSubDirName );
|
|
dwLen = lstrlenW( szDestPathName );
|
|
|
|
if ( szDestPathName[dwLen-1] != L'\\' )
|
|
{
|
|
szDestPathName[dwLen++] = L'\\';
|
|
szDestPathName[dwLen] = L'\0';
|
|
}
|
|
//
|
|
// Create the new directory, if necessary
|
|
//
|
|
if ( !QfsCreateDirectory ( szDestPathName, NULL ) )
|
|
{
|
|
status = GetLastError();
|
|
if ( status != ERROR_ALREADY_EXISTS )
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[CP] CpRestoreCheckpointFiles: Unable to create directory %1!ws!, error %2!d!\n",
|
|
szDestPathName,
|
|
status);
|
|
CL_LOGFAILURE( status );
|
|
goto FnExit;
|
|
}
|
|
}
|
|
|
|
status = ERROR_SUCCESS;
|
|
|
|
while ( status == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// Copy the checkpoint file to the destination
|
|
//
|
|
lstrcpyW( szSourceFileName, szSourcePathName );
|
|
lstrcatW( szSourceFileName, FindData.cFileName );
|
|
lstrcpyW( szDestFileName, szDestPathName );
|
|
lstrcatW( szDestFileName, FindData.cFileName );
|
|
|
|
status = QfsCopyFile( szSourceFileName, szDestFileName, FALSE );
|
|
if ( !status )
|
|
{
|
|
status = GetLastError();
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CpRestoreCheckpointFiles: Unable to copy file %1!ws! to %2!ws!, Error = %3!d!\n",
|
|
szSourceFileName,
|
|
szDestFileName,
|
|
status);
|
|
CL_LOGFAILURE( status );
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Set the file attribute to normal. Continue even if you
|
|
// fail in this step but log an error.
|
|
//
|
|
if ( !QfsSetFileAttributes( szDestFileName, FILE_ATTRIBUTE_NORMAL ) )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CpRestoreCheckpointFiles::Error in changing %1!ws! attribute to NORMAL\n",
|
|
szDestFileName);
|
|
}
|
|
|
|
if ( QfsFindNextFile( hFindFile, &FindData ) )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
} else
|
|
{
|
|
status = GetLastError();
|
|
}
|
|
}
|
|
|
|
if ( status == ERROR_NO_MORE_FILES )
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
} else
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[CP] CpRestoreCheckpointFiles: FindNextFile failed !!!\n");
|
|
}
|
|
|
|
FnExit:
|
|
LocalFree( szSourcePathName );
|
|
LocalFree( szSourceFileName );
|
|
QfsFindCloseIfValid( hFindFile );
|
|
return(status);
|
|
}
|
|
|