Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1197 lines
37 KiB

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
restore.c
Abstract:
Functions supporting the restoration of the cluster database
to the quorum disk
Author:
Chittur Subbaraman (chitturs) 27-Oct-1998
Revision History:
--*/
#include "initp.h"
#include "winioctl.h"
#include <stdio.h>
#include <stdlib.h>
//
// Static global variables used only in this file
//
// static LPWSTR szRdbpNodeNameList = NULL;
// static DWORD dwRdbpNodeCount = 0;
/****
@func DWORD | RdbStopSvcOnNodes | Stop the requested service
on the given node list
@parm IN PNM_NODE_ENUM2 | pNodeEnum | Pointer to the list of
nodes in which the requested service has to be stopped.
@rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
@comm This function attempts to stop the chosen service on the chosen
list of nodes. If it fails in stopping the service on any
one of the nodes, it returns a Win32 error code.
At this time, this function DOES NOT STOP a cluster service
which is run as a process in a remote node.
@xref <f RdbStartSvcOnNodes>
****/
DWORD
RdbStopSvcOnNodes(
IN PNM_NODE_ENUM2 pNodeEnum,
IN LPCWSTR lpszServiceName
)
{
SC_HANDLE hService;
SC_HANDLE hSCManager;
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwRetryTime;
DWORD dwRetryTick;
SERVICE_STATUS serviceStatus;
WCHAR szNodeName[CS_MAX_NODE_NAME_LENGTH + 1];
DWORD i;
BOOL bStopCommandGiven;
//
// Chittur Subbaraman (chitturs) - 10/30/98
//
#if 0
//
// Allocate storage for the node names which you would use to
// start the service later. Memory is freed in RdbpStartSvcOnNodes
//
if ( pNodeEnum->NodeCount > 0 )
{
szRdbpNodeNameList = ( LPWSTR ) LocalAlloc( LMEM_FIXED,
sizeof ( WCHAR) *
( CS_MAX_NODE_NAME_LENGTH + 1 ) *
pNodeEnum->NodeCount );
if ( szRdbpNodeNameList == NULL )
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStopSvcOnNodes: Unable to allocate memory for node names, Error = %1!d!\n",
GetLastError());
}
}
#endif
//
// Walk through the list of nodes
//
for ( i=0; i<pNodeEnum->NodeCount; i++ )
{
lstrcpyW( szNodeName, pNodeEnum->NodeList[i].NodeName );
//
// Skip the local node, if it is included in the list
//
if ( ( lstrcmpW ( szNodeName, NmLocalNodeName ) == 0 ) )
{
continue;
}
//
// Try for 2 minutes max to stop the service on a node. Retry
// in steps of 5 secs.
//
dwRetryTime = 120 * 1000;
dwRetryTick = 05 * 1000;
//
// Open a handle to the service control manager
//
hSCManager = OpenSCManager( szNodeName,
NULL,
SC_MANAGER_ALL_ACCESS );
if ( hSCManager == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStopSvcOnNodes: Unable to open SC manager on node %1!ws!, Error = %2!d!\n",
szNodeName,
dwStatus);
continue;
}
//
// Open a handle to the service
//
hService = OpenService( hSCManager,
lpszServiceName,
SERVICE_ALL_ACCESS );
CloseServiceHandle( hSCManager );
if ( hService == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStopSvcOnNodes: Unable to open handle to %1!ws! service on node %2!ws!, Error = %3!d!\n",
lpszServiceName,
szNodeName,
dwStatus);
continue;
}
//
// Check whether the service is already in the SERVICE_STOPPED
// state.
//
if ( QueryServiceStatus( hService,
&serviceStatus ) )
{
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! already stopped\n",
lpszServiceName,
szNodeName);
CloseServiceHandle( hService );
continue;
}
}
bStopCommandGiven = FALSE;
while ( TRUE )
{
dwStatus = ERROR_SUCCESS;
if ( bStopCommandGiven == TRUE )
{
if ( QueryServiceStatus( hService,
&serviceStatus ) )
{
if ( serviceStatus.dwCurrentState == SERVICE_STOPPED )
{
//
// Succeeded in stopping the service
//
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! stopped successfully\n",
lpszServiceName,
szNodeName);
break;
}
} else
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbStopSvcOnNodes: Error %3!d! in querying status of %1!ws! on node %2!ws!\n",
lpszServiceName,
szNodeName,
dwStatus);
}
} else
{
if ( ControlService( hService,
SERVICE_CONTROL_STOP,
&serviceStatus ) )
{
bStopCommandGiven = TRUE;
dwStatus = ERROR_SUCCESS;
} else
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbStopSvcOnNodes: Error %3!d! in trying to stop %1!ws! on node %2!ws!\n",
lpszServiceName,
szNodeName,
dwStatus);
}
}
if ( ( dwStatus == ERROR_EXCEPTION_IN_SERVICE ) ||
( dwStatus == ERROR_PROCESS_ABORTED ) ||
( dwStatus == ERROR_SERVICE_NOT_ACTIVE ) )
{
//
// The service is essentially in a terminated state
//
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStopSvcOnNodes: %1!ws! on node %2!ws! died/inactive\n",
lpszServiceName,
szNodeName);
dwStatus = ERROR_SUCCESS;
break;
}
if ( ( dwRetryTime -= dwRetryTick ) <= 0 )
{
//
// All tries to stop the service failed, exit from this
// function with an error code
//
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStopSvcOnNodes: Service %1!ws! service on node %2!ws! did not stop, giving up...\n",
lpszServiceName,
szNodeName);
dwStatus = ERROR_TIMEOUT;
break;
}
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbStopSvcOnNodes: Trying to stop %1!ws! on node %2!ws!\n",
lpszServiceName,
szNodeName);
//
// Sleep for a while and retry stopping the service
//
Sleep( dwRetryTick );
} // while
CloseServiceHandle( hService );
if ( dwStatus != ERROR_SUCCESS )
{
goto FnExit;
}
#if 0
//
// Save the node name for later use when starting the service
//
if ( szRdbpNodeNameList != NULL )
{
lstrcpyW( szRdbpNodeNameList + dwRdbpNodeCount *
( CS_MAX_NODE_NAME_LENGTH + 1 ),
szNodeName );
dwRdbpNodeCount++;
}
#endif
} // for
FnExit:
return( dwStatus );
}
/****
@func DWORD | RdbGetRestoreDbParams | Check the registry and see
whether the restore database option is set. If so, get the
params.
@parm IN HKEY | hKey | Handle to the cluster service parameters key
@comm This function attempts read the registry and return the
parameters for the restore database operation.
@xref <f CspGetServiceParams>
****/
VOID
RdbGetRestoreDbParams(
IN HKEY hClusSvcKey
)
{
DWORD dwLength = 0;
DWORD dwType;
DWORD dwStatus;
DWORD dwForceDatabaseRestore;
//
// Chittur Subbaraman (chitturs) - 10/30/98
//
if ( hClusSvcKey == NULL )
{
return;
}
//
// Try to query the clussvc parameters key. If the RestoreDatabase
// value is present, then get the length of the restore database
// path.
//
if ( ClRtlRegQueryString( hClusSvcKey,
CLUSREG_NAME_SVC_PARAM_RESTORE_DB,
REG_SZ,
&CsDatabaseRestorePath,
&dwLength,
&dwLength ) != ERROR_SUCCESS )
{
goto FnExit;
}
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbGetRestoreDbparams: Restore Cluster Database is in progress...\n");
CsDatabaseRestore = TRUE;
//
// Try to query the clussvc parameters key for the ForceRestoreDatabase
// value. Don't bother to delete the param, since the
// RestoreClusterDatabase API will do it.
//
if ( ClRtlRegQueryDword( hClusSvcKey,
CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB,
&dwForceDatabaseRestore,
NULL ) != ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbGetRestoreDbparams: ForceRestoreDatabase params key is absent or unreadable\n"
);
goto FnExit;
}
CsForceDatabaseRestore = TRUE;
//
// Try to query the clussvc parameters key for the NewQuorumDriveLetter
// value. Check for the validity of the drive letter later when
// you attempt to fix up stuff.
//
dwLength = 0;
if ( ClRtlRegQueryString( hClusSvcKey,
CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER,
REG_SZ,
&CsQuorumDriveLetter,
&dwLength,
&dwLength ) != ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbGetRestoreDbparams: NewQuorumDriveLetter params key is absent or unreadable\n"
);
}
FnExit:
//
// Make sure you delete these registry values read above. It is OK if you fail in finding
// some of these values. Note that the RestoreClusterDatabase API will also try to clean
// up these values. We cannot assume that the API will clean up these values since the
// values could be set by (a) ASR (b) A user by hand, and not always by the API.
//
RdbpDeleteRestoreDbParams();
}
/****
@func DWORD | RdbFixupQuorumDiskSignature | Fixup the quorum disk
signature with the supplied value, if necessary
@parm IN DWORD | dwSignature | The new signature which must be
written to the quorum disk.
@rdesc Returns a non-zero value if successful. 0 on failure.
@comm This function attempts to write the given signature into
the physical quorum disk, if necessary.
@xref <f RdbStartSvcOnNodes>
****/
BOOL
RdbFixupQuorumDiskSignature(
IN DWORD dwSignature
)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwStatus;
BOOL bStatus = 1;
//
// Chittur Subbaraman (chitturs) - 10/30/98
//
if ( ( dwSignature == 0 ) ||
( lstrlenW ( CsQuorumDriveLetter ) != 2 ) ||
( !iswalpha( CsQuorumDriveLetter[0] ) ) ||
( CsQuorumDriveLetter[1] != L':' ) )
{
bStatus = 0;
goto FnExit;
}
//
// Now try to open the quorum disk device
//
if ( ( dwStatus = RdbpOpenDiskDevice ( CsQuorumDriveLetter, &hFile ) )
!= ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbFixupQuorumDiskSignature: Error %1!d! in opening %2!ws!\n",
dwStatus,
CsQuorumDriveLetter
);
bStatus = 0;
goto FnExit;
}
//
// Get the signature from the drive, compare it with the input
// parameter and if they are different, write new signature to
// disk.
//
if ( ( dwStatus = RdbpCompareAndWriteSignatureToDisk( hFile, dwSignature ) )
!= ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbFixupQuorumDiskSignature: Error %1!d! in attempting to write signature to %2!ws!\n",
dwStatus,
CsQuorumDriveLetter
);
bStatus = 0;
goto FnExit;
}
FnExit:
if ( hFile != INVALID_HANDLE_VALUE )
{
CloseHandle( hFile );
}
return ( bStatus );
}
/****
@func DWORD | RdbpOpenDiskDevice | Open and get a handle
to a physical disk device
@parm IN LPCWSTR | lpDriveLetter | The disk drive letter.
@parm OUT PHANDLE | pFileHandle | Pointer to the handle to the open
device.
@rdesc Returns ERROR_SUCCESS if successful. A Win32 error code on
failure.
@comm This function attempts to open a disk device and return a
handle to it. Different ways are used to open the device.
@xref <f RdbFixupQuorumDiskSignature>
****/
DWORD
RdbpOpenDiskDevice(
IN LPCWSTR lpDriveLetter,
OUT PHANDLE pFileHandle
)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD accessMode;
DWORD shareMode;
DWORD dwStatus;
BOOL bFailed = FALSE;
WCHAR deviceNameString[128];
//
// Chittur Subbaraman (chitturs) - 10/30/98
//
// Note it is important to access the device with 0 access mode
// so that the file open code won't do extra I/O to the device.
//
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
accessMode = GENERIC_READ | GENERIC_WRITE;
lstrcpyW( deviceNameString, L"\\\\.\\" );
lstrcatW( deviceNameString, lpDriveLetter );
hFile = CreateFileW( deviceNameString,
accessMode,
shareMode,
NULL,
OPEN_EXISTING,
0,
NULL );
if ( hFile == INVALID_HANDLE_VALUE )
{
dwStatus = GetLastError();
goto FnExit;
}
dwStatus = ERROR_SUCCESS;
*pFileHandle = hFile;
FnExit:
return( dwStatus );
}
/****
@func DWORD | RdbpCompareAndWriteSignatureToDisk | Compare the
signature on disk with the input parameter and if they
are not the same, write the input parameter as a new signature.
@parm IN HANDLE | hFile | Handle to the disk device.
@parm IN DWORD | dwSignature | Signature to be compared with
exisiting disk signature.
@rdesc Returns ERROR_SUCCESS if successful. A Win32 error code on
failure.
@comm This function attempts to first get the drive layout, read the
signature information, and then if necessary write back a
new signature to the drive. [This code is stolen from Rod's
clusdisk\test\disktest.c and then adapted to suit our needs.]
@xref <f RdbFixupQuorumDiskSignature>
****/
DWORD
RdbpCompareAndWriteSignatureToDisk(
IN HANDLE hFile,
IN DWORD dwSignature
)
{
DWORD dwStatus;
DWORD dwBytesReturned;
DWORD dwDriveLayoutSize;
PDRIVE_LAYOUT_INFORMATION pDriveLayout = NULL;
//
// Chittur Subbaraman (chitturs) - 10/30/98
//
if ( !ClRtlGetDriveLayoutTable( hFile, &pDriveLayout, &dwBytesReturned )) {
dwStatus = GetLastError();
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbpCompareAndWriteSignatureToDisk: Error %1!d! in getting "
"drive layout from %2!ws!\n",
dwStatus,
CsQuorumDriveLetter
);
goto FnExit;
}
dwDriveLayoutSize = sizeof( DRIVE_LAYOUT_INFORMATION ) +
( sizeof( PARTITION_INFORMATION ) *
( pDriveLayout->PartitionCount - 1 ) );
if ( dwBytesReturned < dwDriveLayoutSize )
{
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbpCompareAndWriteSignatureToDisk: Error reading driveLayout information. Expected %1!u! bytes, got %2!u! bytes.\n",
dwDriveLayoutSize,
dwBytesReturned
);
dwStatus = ERROR_INSUFFICIENT_BUFFER;
goto FnExit;
}
if ( pDriveLayout->Signature == dwSignature )
{
dwStatus = ERROR_SUCCESS;
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbpCompareAndWriteSignatureToDisk: Disk %1!ws! signature is same as in registry. No fixup needed\n",
CsQuorumDriveLetter
);
goto FnExit;
}
//
// Change just the signature field and send an ioctl down
//
pDriveLayout->Signature = dwSignature;
if ( !DeviceIoControl( hFile,
IOCTL_DISK_SET_DRIVE_LAYOUT,
pDriveLayout,
dwDriveLayoutSize,
NULL,
0,
&dwBytesReturned,
FALSE ) )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbpCompareAndWriteSignatureToDisk: Error %1!d! in setting drive layout to %2!ws!\n",
dwStatus,
CsQuorumDriveLetter
);
goto FnExit;
}
dwStatus = ERROR_SUCCESS;
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbpCompareAndWriteSignatureToDisk: Quorum disk signature fixed successfully\n"
);
FnExit:
if ( pDriveLayout != NULL ) {
LocalFree( pDriveLayout );
}
return( dwStatus );
}
#if 0
/****
@func DWORD | RdbStartSvcOnNodes | Start the cluster service on
the nodes in which you stopped the service.
@parm IN LPCWSTR | lpszServiceName | Name of the service to start.
@rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
@comm This function attempts to start the service on the nodes on
which it stopped the service for a restoration operation.
@xref <f RdbStopSvcOnNodes>
****/
DWORD
RdbStartSvcOnNodes(
IN LPCWSTR lpszServiceName
)
{
SC_HANDLE hService;
SC_HANDLE hSCManager;
DWORD dwStatus = ERROR_SUCCESS;
SERVICE_STATUS serviceStatus;
WCHAR szNodeName[CS_MAX_NODE_NAME_LENGTH + 1];
DWORD i;
//
// Chittur Subbaraman (chitturs) - 11/4/98
//
// Walk through the list of nodes
//
for ( i=0; i<dwRdbpNodeCount; i++ )
{
lstrcpyW( szNodeName, szRdbpNodeNameList + i *
( CS_MAX_NODE_NAME_LENGTH + 1 ) );
//
// Open a handle to the service control manager
//
hSCManager = OpenSCManager( szNodeName,
NULL,
SC_MANAGER_ALL_ACCESS );
if ( hSCManager == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStartSvcOnNodes: Unable to open SC manager on node %1!ws!, Error = %2!d!\n",
szNodeName,
dwStatus);
continue;
}
//
// Open a handle to the service
//
hService = OpenService( hSCManager,
lpszServiceName,
SERVICE_ALL_ACCESS );
CloseServiceHandle( hSCManager );
if ( hService == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbStartSvcOnNodes: Unable to open handle to %1!ws! service on node %2!ws!, Error = %3!d!\n",
lpszServiceName,
szNodeName,
dwStatus);
continue;
}
//
// Check whether the service is already started.
//
if ( QueryServiceStatus( hService,
&serviceStatus ) )
{
if ( ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) ||
( serviceStatus.dwCurrentState == SERVICE_START_PENDING ) )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbStartSvcOnNodes: %1!ws! on node %2!ws! already started\n",
lpszServiceName,
szNodeName);
CloseServiceHandle( hService );
continue;
}
}
//
// Now, start the cluster service
//
if ( !StartService( hService,
0,
NULL ) )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbStartSvcOnNodes: Unable to start cluster service on %1!ws!\n",
szNodeName
);
} else
{
ClRtlLogPrint(LOG_ERROR,
"[INIT] RdbStartSvcOnNodes: Cluster service started on %1!ws!\n",
szNodeName
);
}
//
// And, close the current handle
//
CloseServiceHandle( hService );
} // for
//
// Now free the memory
//
LocalFree( szRdbpNodeNameList );
return( dwStatus );
}
#endif
/****
@func DWORD | RdbInitialize | This function performs the
initialization steps necessary for the restore database
manager. Specifically, copy the most recent checkpoint
file from the backup path to the cluster directory overwriting
the CLUSDB there.
@rdesc Returns a Win32 error code if the operation is
unsuccessful. ERROR_SUCCESS on success.
@xref <f DmInitialize>
****/
DWORD
RdbInitialize(
VOID
)
{
HANDLE hFindFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW FindData;
DWORD dwStatus;
WCHAR szDestFileName[MAX_PATH];
LPWSTR szSourceFileName = NULL;
LPWSTR szSourcePathName = NULL;
DWORD dwLen;
WIN32_FILE_ATTRIBUTE_DATA FileAttributes;
LARGE_INTEGER liFileCreationTime;
LARGE_INTEGER liMaxFileCreationTime;
WCHAR szCheckpointFileName[MAX_PATH];
WCHAR szClusterDir[MAX_PATH];
LPCWSTR lpszPathName = CsDatabaseRestorePath;
//
// Chittur Subbaraman (chitturs) - 12/4/99
//
//
// If there is no cluster database restore in progress, don't do anything.
//
if( CsDatabaseRestore == FALSE )
{
return( ERROR_SUCCESS );
}
ClRtlLogPrint(LOG_NOISE, "[INIT] RdbInitialize: Entry...\n");
dwLen = lstrlenW ( lpszPathName );
//
// 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 destination path is concerned, it is system-dependent
// and static memory allocation for that would suffice.
//
szSourcePathName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
( dwLen + 25 ) *
sizeof ( WCHAR ) );
if ( szSourcePathName == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Error %1!d! in allocating memory for %2!ws!\n",
dwStatus,
lpszPathName);
goto FnExit;
}
lstrcpyW ( szSourcePathName, lpszPathName );
//
// If the client-supplied path is not already terminated with '\',
// then add it.
//
if ( szSourcePathName [dwLen-1] != L'\\' )
{
szSourcePathName [dwLen++] = L'\\';
szSourcePathName [dwLen] = L'\0';
}
lstrcatW ( szSourcePathName, L"CLUSBACKUP.DAT" );
//
// Try to find the CLUSBACKUP.DAT file in the directory
//
hFindFile = FindFirstFileW( szSourcePathName, &FindData );
//
// Reuse the source path name variable
//
szSourcePathName[dwLen] = L'\0';
if ( hFindFile == INVALID_HANDLE_VALUE )
{
dwStatus = GetLastError();
if ( dwStatus != ERROR_FILE_NOT_FOUND )
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Path %1!ws! unavailable, Error = %2!d!\n",
szSourcePathName,
dwStatus);
} else
{
dwStatus = ERROR_DATABASE_BACKUP_CORRUPT;
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Backup procedure from %1!ws! not fully"
" successful, can't restore checkpoint to CLUSDB, Error = %2!d! !!!\n",
szSourcePathName,
dwStatus);
}
goto FnExit;
}
FindClose ( hFindFile );
lstrcatW( szSourcePathName, L"chk*.tmp" );
//
// Try to find the first chk*.tmp file in the directory
//
hFindFile = FindFirstFileW( szSourcePathName, &FindData );
//
// Reuse the source path name variable
//
szSourcePathName[dwLen] = L'\0';
if ( hFindFile == INVALID_HANDLE_VALUE )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Error %2!d! in trying"
"to find chk*.tmp file in path %1!ws!\r\n",
szSourcePathName,
dwStatus);
goto FnExit;
}
szSourceFileName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
( lstrlenW ( szSourcePathName ) + MAX_PATH ) *
sizeof ( WCHAR ) );
if ( szSourceFileName == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Error %1!d! in allocating memory for source file name\n",
dwStatus);
goto FnExit;
}
dwStatus = ERROR_SUCCESS;
liMaxFileCreationTime.QuadPart = 0;
//
// Now, find the most recent chk*.tmp file from the source path
//
while ( dwStatus == ERROR_SUCCESS )
{
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
goto skip;
}
lstrcpyW( szSourceFileName, szSourcePathName );
lstrcatW( szSourceFileName, FindData.cFileName );
if ( !GetFileAttributesExW( szSourceFileName,
GetFileExInfoStandard,
&FileAttributes ) )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL, "[INIT] RdbInitialize: Error %1!d! in getting file"
" attributes for %2!ws!\n",
dwStatus,
szSourceFileName);
goto FnExit;
}
liFileCreationTime.HighPart = FileAttributes.ftCreationTime.dwHighDateTime;
liFileCreationTime.LowPart = FileAttributes.ftCreationTime.dwLowDateTime;
if ( liFileCreationTime.QuadPart > liMaxFileCreationTime.QuadPart )
{
liMaxFileCreationTime.QuadPart = liFileCreationTime.QuadPart;
lstrcpyW( szCheckpointFileName, FindData.cFileName );
}
skip:
if ( FindNextFileW( hFindFile, &FindData ) )
{
dwStatus = ERROR_SUCCESS;
} else
{
dwStatus = GetLastError();
}
}
if ( dwStatus == ERROR_NO_MORE_FILES )
{
dwStatus = ERROR_SUCCESS;
} else
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: FindNextFile failed, error=%1!d!\n",
dwStatus);
goto FnExit;
}
//
// Get the directory where the cluster is installed
//
if ( ( dwStatus = ClRtlGetClusterDirectory( szClusterDir, MAX_PATH ) )
!= ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Error %1!d! in getting cluster dir !!!\n",
dwStatus);
goto FnExit;
}
lstrcpyW( szSourceFileName, szSourcePathName );
lstrcatW( szSourceFileName, szCheckpointFileName );
lstrcpyW( szDestFileName, szClusterDir );
dwLen = lstrlenW( szDestFileName );
if ( szDestFileName[dwLen-1] != L'\\' )
{
szDestFileName[dwLen++] = L'\\';
szDestFileName[dwLen] = L'\0';
}
#ifdef OLD_WAY
lstrcatW ( szDestFileName, L"CLUSDB" );
#else // OLD_WAY
lstrcatW ( szDestFileName, CLUSTER_DATABASE_NAME );
#endif // OLD_WAY
//
// Set the destination file attribute to normal. Continue even
// if you fail in this step because you will fail in the
// copy if this error is fatal.
//
SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL );
//
// Now try to copy the checkpoint file to CLUSDB
//
dwStatus = CopyFileW( szSourceFileName, szDestFileName, FALSE );
if ( !dwStatus )
{
//
// You failed in copying. Check whether you encountered a
// sharing violation. If so, try unloading the cluster hive and
// then retry.
//
dwStatus = GetLastError();
if ( dwStatus == ERROR_SHARING_VIOLATION )
{
dwStatus = RdbpUnloadClusterHive( );
if ( dwStatus == ERROR_SUCCESS )
{
SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL );
dwStatus = CopyFileW( szSourceFileName, szDestFileName, FALSE );
if ( !dwStatus )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Unable to copy file %1!ws! "
"to %2!ws! for a second time, Error = %3!d!\n",
szSourceFileName,
szDestFileName,
dwStatus);
goto FnExit;
}
} else
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Unable to unload cluster hive, Error = %1!d!\n",
dwStatus);
goto FnExit;
}
} else
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Unable to copy file %1!ws! "
"to %2!ws! for the first time, Error = %3!d!\n",
szSourceFileName,
szDestFileName,
dwStatus);
goto FnExit;
}
}
//
// Set the destination file attribute to normal.
//
if ( !SetFileAttributesW( szDestFileName, FILE_ATTRIBUTE_NORMAL ) )
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbInitialize: Unable to change the %1!ws! "
"attributes to normal, Error = %2!d!\n",
szDestFileName,
dwStatus);
goto FnExit;
}
dwStatus = ERROR_SUCCESS;
FnExit:
if ( hFindFile != INVALID_HANDLE_VALUE )
{
FindClose( hFindFile );
}
LocalFree( szSourcePathName );
LocalFree( szSourceFileName );
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbInitialize: Exit with Status = %1!d!...\n",
dwStatus);
return( dwStatus );
}
/****
@func DWORD | RdbpUnloadClusterHive | Unload the cluster hive
@rdesc Returns a Win32 error code if the operation is
unsuccessful. ERROR_SUCCESS on success.
@xref <f RdbInitialize>
****/
DWORD
RdbpUnloadClusterHive(
VOID
)
{
BOOLEAN bWasEnabled;
DWORD dwStatus;
//
// Chittur Subbaraman (chitturs) - 12/4/99
//
dwStatus = ClRtlEnableThreadPrivilege( SE_RESTORE_PRIVILEGE,
&bWasEnabled );
if ( dwStatus != ERROR_SUCCESS )
{
if ( dwStatus == STATUS_PRIVILEGE_NOT_HELD )
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbpUnloadClusterHive: Restore privilege not held by client\n");
} else
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbpUnloadClusterHive: Attempt to enable restore "
"privilege failed, Error = %1!d!\n",
dwStatus);
}
goto FnExit;
}
dwStatus = RegUnLoadKeyW( HKEY_LOCAL_MACHINE,
CLUSREG_KEYNAME_CLUSTER );
ClRtlRestoreThreadPrivilege( SE_RESTORE_PRIVILEGE,
bWasEnabled );
FnExit:
return( dwStatus );
}
/****
@func DWORD | RdbpDeleteRestoreDbParams | Clean up the restore parameters stored
under HKLM\System\CCC\Services\Clussvc\Parameters. The RestoreClusterDatabase
API will also attempt to do this.
@comm This function attempts clean the registry parameters for the restore database
operation.
@rdesc Returns a Win32 error code if the opening of the params key is unsuccessful.
ERROR_SUCCESS on success.
@xref <f RdbGetRestoreDbParams>
****/
DWORD
RdbpDeleteRestoreDbParams(
VOID
)
{
HKEY hClusSvcKey = NULL;
DWORD dwStatus;
//
// Chittur Subbaraman (chitturs) - 08/28/2000
//
if( CsDatabaseRestore == FALSE )
{
return( ERROR_SUCCESS );
}
ClRtlLogPrint(LOG_NOISE, "[INIT] RdbDeleteRestoreDbParams: Entry...\n");
//
// Open key to SYSTEM\CurrentControlSet\Services\ClusSvc\Parameters
//
dwStatus = RegOpenKeyW( HKEY_LOCAL_MACHINE,
CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
&hClusSvcKey );
if( dwStatus != ERROR_SUCCESS )
{
ClRtlLogPrint(LOG_UNUSUAL,
"[INIT] RdbDeleteRestoreDbParams: Unable to open clussvc params key, error=%1!u!...\n",
dwStatus);
goto FnExit;
}
//
// Try to delete the values you set. You may fail in these steps, because all these values need
// not be present in the registry.
//
dwStatus = RegDeleteValueW( hClusSvcKey,
CLUSREG_NAME_SVC_PARAM_RESTORE_DB );
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
dwStatus,
CLUSREG_NAME_SVC_PARAM_RESTORE_DB);
}
dwStatus = RegDeleteValueW( hClusSvcKey,
CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB );
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
dwStatus,
CLUSREG_NAME_SVC_PARAM_FORCE_RESTORE_DB);
}
dwStatus = RegDeleteValueW( hClusSvcKey,
CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER );
if ( ( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ClRtlLogPrint(LOG_NOISE,
"[INIT] RdbDeleteRestoreDbParams: Unable to delete %2!ws! param value, error=%1!u!...\n",
dwStatus,
CLUSREG_NAME_SVC_PARAM_QUORUM_DRIVE_LETTER);
}
dwStatus = ERROR_SUCCESS;
FnExit:
if ( hClusSvcKey != NULL )
{
RegCloseKey( hClusSvcKey );
}
ClRtlLogPrint(LOG_NOISE, "[INIT] RdbDeleteRestoreDbParams: Exit with status=%1!u!...\n",
dwStatus);
return( dwStatus );
}