1014 lines
27 KiB
C
1014 lines
27 KiB
C
/*++
|
||
|
||
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"
|
||
|
||
|
||
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) {
|
||
//
|
||
// 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) {
|
||
SetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_NORMAL);
|
||
SetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_NORMAL);
|
||
}
|
||
|
||
|
||
//
|
||
// Create the new directory.
|
||
//
|
||
if (!CreateDirectory(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 (!CopyFile(OldCheckpointFile, NewCheckpointFile, FALSE)) {
|
||
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 (!SetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_READONLY)
|
||
||
|
||
!SetFileAttributes(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) {
|
||
SetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_NORMAL);
|
||
SetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_NORMAL);
|
||
}
|
||
|
||
|
||
//
|
||
// Create the new directory.
|
||
//
|
||
if (!CreateDirectory(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 (!CopyFile(OldCheckpointFile, NewCheckpointFile, FALSE)) {
|
||
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 (!SetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_READONLY)
|
||
||
|
||
!SetFileAttributes(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;
|
||
HANDLE hFindFile = INVALID_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 = FindFirstFile( szSourcePathName, &FindData );
|
||
//
|
||
// Reuse the source path name variable
|
||
//
|
||
szSourcePathName[dwLen] = L'\0';
|
||
if ( hFindFile == INVALID_HANDLE_VALUE )
|
||
{
|
||
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 ( !CreateDirectory ( 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 = CopyFileW( 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 ( !SetFileAttributes( szDestFileName, FILE_ATTRIBUTE_NORMAL ) )
|
||
{
|
||
ClRtlLogPrint(LOG_UNUSUAL,
|
||
"[CP] CpRestoreCheckpointFiles::Error in changing %1!ws! attribute to NORMAL\n",
|
||
szDestFileName);
|
||
}
|
||
|
||
if ( FindNextFile( 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 );
|
||
if ( hFindFile != INVALID_HANDLE_VALUE )
|
||
{
|
||
FindClose( hFindFile );
|
||
}
|
||
return(status);
|
||
}
|
||
|