|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2002 Microsoft Corporation
//
// Module Name:
// CClusCfgNodeInfo.cpp
//
// Description:
// This file contains the definition of the CClusCfgNodeInfo
// class.
//
// The class CClusCfgNodeInfo is the representation of a
// computer that can be a cluster node. It implements the
// IClusCfgNodeInfo interface.
//
// Maintained By:
// Galen Barbee (GalenB) 21-FEB-2000
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
#include "Pch.h"
#include <ClusRTL.h>
#include "CClusCfgNodeInfo.h"
#include "CClusCfgClusterInfo.h"
//////////////////////////////////////////////////////////////////////////////
// Constant Definitions
//////////////////////////////////////////////////////////////////////////////
DEFINE_THISCLASS( "CClusCfgNodeInfo" );
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusCfgNodeInfo class
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::S_HrCreateInstance
//
// Description:
// Create a CClusCfgNodeInfo instance.
//
// Arguments:
// None.
//
// Return Values:
// Pointer to CClusCfgNodeInfo instance.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::S_HrCreateInstance( IUnknown ** ppunkOut ) { TraceFunc( "" );
HRESULT hr = S_OK; CClusCfgNodeInfo * pccni = NULL;
if ( ppunkOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if:
pccni = new CClusCfgNodeInfo(); if ( pccni == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if: error allocating object
hr = THR( pccni->HrInit() ); if ( FAILED( hr ) ) { goto Cleanup; } // if: HrInit() failed
hr = THR( pccni->TypeSafeQI( IUnknown, ppunkOut ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: QI failed
Cleanup:
if ( FAILED( hr ) ) { LogMsg( L"[SRV] CClusCfgNodeInfo::S_HrCreateInstance() failed. (hr = %#08x)", hr ); } // if:
if ( pccni != NULL ) { pccni->Release(); } // if:
HRETURN( hr );
} //*** CClusCfgNodeInfo::S_HrCreateInstance
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::CClusCfgNodeInfo
//
// Description:
// Constructor of the CClusCfgNodeInfo class. This initializes
// the m_cRef variable to 1 instead of 0 to account of possible
// QueryInterface failure in DllGetClassObject.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CClusCfgNodeInfo::CClusCfgNodeInfo( void ) : m_cRef( 1 ) , m_lcid( LOCALE_NEUTRAL ) , m_fIsClusterNode( false ) { TraceFunc( "" );
// Increment the count of components in memory so the DLL hosting this
// object cannot be unloaded.
InterlockedIncrement( &g_cObjects );
Assert( m_bstrFullDnsName == NULL ); Assert( m_picccCallback == NULL ); Assert( m_pIWbemServices == NULL ); Assert( m_punkClusterInfo == NULL ); Assert( m_cMaxNodes == 0 ); Assert( m_rgdluDrives[ 0 ].edluUsage == dluUNKNOWN ); Assert( m_rgdluDrives[ 0 ].psiInfo == NULL );
TraceFuncExit();
} //*** CClusCfgNodeInfo::CClusCfgNodeInfo
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::~CClusCfgNodeInfo
//
// Description:
// Desstructor of the CClusCfgNodeInfo class.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CClusCfgNodeInfo::~CClusCfgNodeInfo( void ) { TraceFunc( "" );
int idx;
TraceSysFreeString( m_bstrFullDnsName );
if ( m_pIWbemServices != NULL ) { m_pIWbemServices->Release(); } // if:
if ( m_picccCallback != NULL ) { m_picccCallback->Release(); } // if:
if ( m_punkClusterInfo != NULL ) { m_punkClusterInfo->Release(); } // if:
for ( idx = 0; idx < 26; idx++ ) { TraceFree( m_rgdluDrives[ idx ].psiInfo ); } // for:
// There's going to be one less component in memory. Decrement component count.
InterlockedDecrement( &g_cObjects );
TraceFuncExit();
} //*** CClusCfgNodeInfo::~CClusCfgNodeInfo
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusCfgNodeInfo -- IUknkown interface.
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::AddRef
//
// Description:
// Increment the reference count of this object by one.
//
// Arguments:
// None.
//
// Return Value:
// The new reference count.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CClusCfgNodeInfo::AddRef( void ) { TraceFunc( "[IUnknown]" );
InterlockedIncrement( & m_cRef );
CRETURN( m_cRef );
} //*** CClusCfgNodeInfo::AddRef
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::Release
//
// Description:
// Decrement the reference count of this object by one.
//
// Arguments:
// None.
//
// Return Value:
// The new reference count.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CClusCfgNodeInfo::Release( void ) { TraceFunc( "[IUnknown]" );
LONG cRef;
cRef = InterlockedDecrement( &m_cRef ); if ( cRef == 0 ) { TraceDo( delete this ); } // if: reference count equal to zero
CRETURN( cRef );
} //*** CClusCfgNodeInfo::Release
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::QueryInterface
//
// Description:
// Query this object for the passed in interface.
//
// Arguments:
// riidIn
// Id of interface requested.
//
// ppvOut
// Pointer to the requested interface.
//
// Return Value:
// S_OK
// If the interface is available on this object.
//
// E_NOINTERFACE
// If the interface is not available.
//
// E_POINTER
// ppvOut was NULL.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::QueryInterface( REFIID riidIn , void ** ppvOut ) { TraceQIFunc( riidIn, ppvOut );
HRESULT hr = S_OK;
//
// Validate arguments.
//
Assert( ppvOut != NULL ); if ( ppvOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; }
//
// Handle known interfaces.
//
if ( IsEqualIID( riidIn, IID_IUnknown ) ) { *ppvOut = static_cast< IClusCfgNodeInfo * >( this ); } // if: IUnknown
else if ( IsEqualIID( riidIn, IID_IClusCfgNodeInfo ) ) { *ppvOut = TraceInterface( __THISCLASS__, IClusCfgNodeInfo, this, 0 ); } // else if: IClusCfgNodeInfo
else if ( IsEqualIID( riidIn, IID_IClusCfgWbemServices ) ) { *ppvOut = TraceInterface( __THISCLASS__, IClusCfgWbemServices, this, 0 ); } // else if: IClusCfgWbemServices
else if ( IsEqualIID( riidIn, IID_IClusCfgInitialize ) ) { *ppvOut = TraceInterface( __THISCLASS__, IClusCfgInitialize, this, 0 ); } // else if: IClusCfgInitialize
else { *ppvOut = NULL; hr = E_NOINTERFACE; }
//
// Add a reference to the interface if successful.
//
if ( SUCCEEDED( hr ) ) { ((IUnknown *) *ppvOut)->AddRef(); } // if: success
Cleanup:
QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
} //*** CClusCfgNodeInfo::QueryInterface
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusCfgNodeInfo -- IClusCfgWbemServices
// interface.
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::SetWbemServices
//
// Description:
// Set the WBEM services provider.
//
// Arguments:
// IN IWbemServices pIWbemServicesIn
//
// Return Value:
// S_OK
// Success
//
// E_POINTER
// The pIWbemServicesIn param is NULL.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::SetWbemServices( IWbemServices * pIWbemServicesIn ) { TraceFunc( "[IClusCfgWbemServices]" );
HRESULT hr = S_OK;
if ( pIWbemServicesIn == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_SetWbemServices_Node, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr ); goto Cleanup; } // if:
m_pIWbemServices = pIWbemServicesIn; m_pIWbemServices->AddRef();
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::SetWbemServices
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusCfgNodeInfo -- IClusCfgInitialize interface.
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::Initialize
//
// Description:
// Initialize this component.
//
// Arguments:
// IN IUknown * punkCallbackIn
//
// IN LCID lcidIn
//
// Return Value:
// S_OK
// Success
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::Initialize( IUnknown * punkCallbackIn, LCID lcidIn ) { TraceFunc( "[IClusCfgInitialize]" ); Assert( m_picccCallback == NULL );
HRESULT hr = S_OK;
m_lcid = lcidIn;
if ( punkCallbackIn == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if:
hr = THR( punkCallbackIn->TypeSafeQI( IClusCfgCallback, &m_picccCallback ) );
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::Initialize
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusCfgNodeInfo -- IClusCfgNodeInfo interface.
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetName
//
// Description:
// Return the name of this computer.
//
// Arguments:
//
// Return Value:
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetName( BSTR * pbstrNameOut ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_OK;
if ( pbstrNameOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_NodeInfo_GetName_Pointer, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr ); goto Cleanup; } // if:
*pbstrNameOut = SysAllocString( m_bstrFullDnsName ); if ( *pbstrNameOut == NULL ) { hr = THR( E_OUTOFMEMORY ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetName_Memory, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr ); } // if:
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetName
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::SetName
//
// Description:
// Change the name of this computer.
//
// Arguments:
// IN LPCWSTR pcszNameIn
// The new name for this computer.
// Return Value:
// S_OK
// Success
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::SetName( LPCWSTR pcszNameIn ) { TraceFunc1( "[IClusCfgNodeInfo] pcszNameIn = '%ls'", pcszNameIn == NULL ? L"<null>" : pcszNameIn );
HRESULT hr = THR( E_NOTIMPL );
HRETURN( hr );
} //*** CClusCfgNodeInfo::SetName
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::IsMemberOfCluster
//
// Description:
// Is this computer a member of a cluster?
//
// Arguments:
// None.
//
// Return Value:
// S_OK
// This node is a member of a cluster.
//
// S_FALSE
// This node is not member of a cluster.
//
// Other Win32 errors as HRESULT if GetNodeClusterState() fails.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::IsMemberOfCluster( void ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_FALSE; // default to not a cluster node.
if ( m_fIsClusterNode ) { hr = S_OK; } // if:
HRETURN( hr );
} //*** CClusCfgNodeInfo::IsMemberOfCluster
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetClusterConfigInfo
//
// Description:
// Return the configuration information about the cluster that this
// conputer belongs to.
//
// Arguments:
// OUT IClusCfgClusterInfo ** ppClusCfgClusterInfoOut
// Catches the CClusterConfigurationInfo object.
//
// Return Value:
// S_OK
// Success
//
// E_POINTER
// The out param was NULL.
//
// E_OUTOFMEMORY
// The CClusCfgNodeInfo object could not be allocated.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetClusterConfigInfo( IClusCfgClusterInfo ** ppClusCfgClusterInfoOut ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_OK; HRESULT hrInit = S_OK; IClusCfgSetClusterNodeInfo * pccsgni = NULL;
if ( ppClusCfgClusterInfoOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetClusterConfigInfo, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr ); goto Cleanup; } // if:
if ( m_punkClusterInfo != NULL ) { hr = S_OK; LogMsg( L"[SRV] CClusCfgNodeInfo::GetClusterConfigInfo() skipped object creation." ); goto SkipCreate; } // if:
hr = THR( CClusCfgClusterInfo::S_HrCreateInstance( &m_punkClusterInfo ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
m_punkClusterInfo = TraceInterface( L"CClusCfgClusterInfo", IUnknown, m_punkClusterInfo, 1 );
//
// KB: 01-JUN-200 GalenB
//
// This must be done before the CClusCfgClusterInfo class is initialized.
//
hr = THR( m_punkClusterInfo->TypeSafeQI( IClusCfgSetClusterNodeInfo, &pccsgni ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
hr = THR( pccsgni->SetClusterNodeInfo( this ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// KB: 01-JUN-200 GalenB
//
// This must be done after SetClusterNodeInfo() is called, but before Initialize.
//
hr = THR( HrSetWbemServices( m_punkClusterInfo, m_pIWbemServices ) ); if ( FAILED( hr ) ) { LogMsg( L"[SRV] Could not set the WBEM services on a CClusCfgClusterInfo object. (hr = %#08x)", hr ); goto Cleanup; } // if:
//
// KB: 01-JUN-200 GalenB
//
// This must be done after SetClusterNodeInfo() and HrSetWbemServices are called.
//
hrInit = STHR( HrSetInitialize( m_punkClusterInfo, m_picccCallback, m_lcid ) ); hr = hrInit; // need hrInit later...
if ( FAILED( hr ) ) { LogMsg( L"[SRV] Could not initialize CClusCfgClusterInfo object. (hr = %#08x)", hr ); goto Cleanup; } // if:
SkipCreate:
if ( SUCCEEDED( hr ) ) { Assert( m_punkClusterInfo != NULL ); hr = THR( m_punkClusterInfo->TypeSafeQI( IClusCfgClusterInfo, ppClusCfgClusterInfoOut ) ); } // if:
Cleanup:
//
// If hrInit is not S_OK then it is most likely HR_S_RPC_S_CLUSTER_NODE_DOWN which
// needs to get passed up... Everything else must have succeeded an hr must be
// S_OK too.
//
if ( ( hr == S_OK ) && ( hrInit != S_OK ) ) { hr = hrInit; } // if:
LOG_STATUS_REPORT_MINOR( TASKID_Minor_Server_GetClusterInfo, L"GetClusterConfigInfo() completed.", hr );
if ( pccsgni != NULL ) { pccsgni->Release(); } // if:
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetClusterConfigInfo
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetOSVersion
//
// Description:
// What is the OS version on this computer?
//
// Arguments:
// None.
//
// Return Value:
//
// Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetOSVersion( DWORD * pdwMajorVersionOut, DWORD * pdwMinorVersionOut, WORD * pwSuiteMaskOut, BYTE * pbProductTypeOut, BSTR * pbstrCSDVersionOut ) { TraceFunc( "[IClusCfgNodeInfo]" );
OSVERSIONINFOEX osv; HRESULT hr = S_OK;
osv.dwOSVersionInfoSize = sizeof( osv );
if ( !GetVersionEx( (OSVERSIONINFO *) &osv ) ) { DWORD sc;
sc = TW32( GetLastError() ); hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if: GetVersionEx() failed
if ( pdwMajorVersionOut != NULL ) { *pdwMajorVersionOut = osv.dwMajorVersion; } // if:
if ( pdwMinorVersionOut != NULL ) { *pdwMinorVersionOut = osv.dwMinorVersion; } // if:
if ( pwSuiteMaskOut != NULL ) { *pwSuiteMaskOut = osv.wSuiteMask; } // if:
if ( pbProductTypeOut != NULL ) { *pbProductTypeOut = osv.wProductType; } // if:
if ( pbstrCSDVersionOut != NULL ) { *pbstrCSDVersionOut = SysAllocString( osv.szCSDVersion ); if ( *pbstrCSDVersionOut == NULL ) { hr = THR( E_OUTOFMEMORY ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetOSVersion, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr ); goto Cleanup; } // if:
} // if:
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetOSVersion
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetClusterVersion
//
// Description:
// Return the cluster version information for the cluster this
// computer belongs to.
//
// Arguments:
//
// Return Value:
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetClusterVersion( DWORD * pdwNodeHighestVersion, DWORD * pdwNodeLowestVersion ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_OK;
if ( ( pdwNodeHighestVersion == NULL ) || ( pdwNodeLowestVersion == NULL ) ) { goto BadParams; } // if:
*pdwNodeHighestVersion = CLUSTER_MAKE_VERSION( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION, VER_PRODUCTBUILD ); *pdwNodeLowestVersion = CLUSTER_INTERNAL_PREVIOUS_HIGHEST_VERSION;
goto Cleanup;
BadParams:
hr = THR( E_POINTER ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetClusterVersion, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetClusterVersion
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetDriveLetterMappings
//
// Description:
//
// Arguments:
// None.
//
// Return Value:
//
// Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetDriveLetterMappings( SDriveLetterMapping * pdlmDriveLetterUsageOut ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_FALSE; DWORD sc; DWORD cchDrives = ( 4 * 26 ) + 1; // "C:\<null>" times 26 drive letters
WCHAR * pszDrives = NULL; int idx;
pszDrives = new WCHAR[ cchDrives ]; if ( pszDrives == NULL ) { goto OutOfMemory; } // if:
sc = GetLogicalDriveStrings( cchDrives, pszDrives ); if ( sc == 0 ) { sc = TW32( GetLastError() ); hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if:
if ( sc > cchDrives ) { delete [] pszDrives; pszDrives = NULL;
cchDrives = sc + 1;
pszDrives = new WCHAR[ cchDrives ]; if ( pszDrives == NULL ) { goto OutOfMemory; } // if:
sc = GetLogicalDriveStrings( cchDrives, pszDrives ); if ( sc == 0 ) { sc = TW32( GetLastError() ); hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if:
} // if:
hr = THR( HrComputeDriveLetterUsage( pszDrives ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
hr = THR( HrComputeSystemDriveLetterUsage() ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
hr = THR( HrSetPageFileEnumIndex() ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
hr = THR( HrSetCrashDumpEnumIndex() ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// Load the SCSI bus and port information for each disk in each volume.
//
hr = THR( HrGetVolumeInfo() ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// Scan the drives and find those that are "system" and update any other disks on that bus
// to be "??? on system bus".
//
hr = THR( HrUpdateSystemBusDrives() ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// Now that we have our array properly filled out then we need to copy that information
// back to the caller.
//
for ( idx = 0; idx < 26; idx++ ) { pdlmDriveLetterUsageOut->dluDrives[ idx ] = m_rgdluDrives[ idx ].edluUsage; } // for:
goto Cleanup;
OutOfMemory:
hr = THR( E_OUTOFMEMORY ); STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetDriveLetterMappings_Node, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr );
Cleanup:
delete [] pszDrives;
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetDriveLetterMappings
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetMaxNodeCount
//
// Description:
// Returns the maximun number of nodes for this node's product
// suite type.
//
// Notes:
//
// Parameter:
// pcMaxNodesOut
// The maximum number of nodes allowed by this node's product
// suite type.
//
// Return Value:
// S_OK
// Success.
//
// other HRESULT
// The call failed.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetMaxNodeCount( DWORD * pcMaxNodesOut ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_OK;
if ( pcMaxNodesOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if:
*pcMaxNodesOut = m_cMaxNodes;
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetMaxNodeCount
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::GetProcessorInfo
//
// Description:
// Get the processor information for this node.
//
// Arguments:
// pwProcessorArchitectureOut
// The processor architecture.
//
// pwProcessorLevelOut
// The processor level.
//
// Return Value:
// S_OK
// Success.
//
// other HRESULT
// The call failed.
//
// Remarks:
// See SYSTEM_INFO in MSDN and/or the Platform SDK for more
// information.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CClusCfgNodeInfo::GetProcessorInfo( WORD * pwProcessorArchitectureOut , WORD * pwProcessorLevelOut ) { TraceFunc( "[IClusCfgNodeInfo]" );
HRESULT hr = S_OK;
if ( ( pwProcessorArchitectureOut == NULL ) && ( pwProcessorLevelOut == NULL ) ) { hr = THR( E_POINTER ); goto Cleanup; } // if:
if ( pwProcessorArchitectureOut != NULL ) { *pwProcessorArchitectureOut = m_si.wProcessorArchitecture; } // if:
if ( pwProcessorLevelOut != NULL ) { *pwProcessorLevelOut = m_si.wProcessorLevel; } // if:
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::GetProcessorInfo
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusCfgNodeInfo -- Private Methods.
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrInit
//
// Description:
// Initialize this component.
//
// Arguments:
// None.
//
// Return Value:
// S_OK - Success.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrInit( void ) { TraceFunc( "" );
HRESULT hr = S_OK; DWORD sc; DWORD dwClusterState; DWORD dwSuiteType;
// IUnknown
Assert( m_cRef == 1 );
hr = THR( HrGetComputerName( ComputerNameDnsFullyQualified , &m_bstrFullDnsName , TRUE // fBestEffortIn
) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// Get the cluster state of the node.
// Ignore the case where the service does not exist so that
// EvictCleanup can do its job.
//
sc = GetNodeClusterState( NULL, &dwClusterState ); if ( ( sc != ERROR_SUCCESS ) && ( sc != ERROR_SERVICE_DOES_NOT_EXIST ) ) { hr = HRESULT_FROM_WIN32( TW32( sc ) ); goto Cleanup; } // if : GetClusterState() failed
//
// If the current cluster node state is running or not running then this node is part of a cluster.
//
m_fIsClusterNode = ( dwClusterState == ClusterStateNotRunning ) || ( dwClusterState == ClusterStateRunning );
GetSystemInfo( &m_si );
dwSuiteType = ClRtlGetSuiteType(); Assert( dwSuiteType != 0 ); // we should only run on server SKUs!
if ( dwSuiteType != 0 ) { m_cMaxNodes = ClRtlGetDefaultNodeLimit( dwSuiteType ); } // if:
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrInit
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrComputeDriveLetterUsage
//
// Description:
// Fill the array with the enums that represent the drive letter usage
// and the drive letter string.
//
// Arguments:
//
//
// Return Value:
//
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrComputeDriveLetterUsage( WCHAR * pszDrivesIn ) { TraceFunc( "" ); Assert( pszDrivesIn != NULL );
HRESULT hr = S_OK; WCHAR * pszDrive = pszDrivesIn; UINT uiType; int idx;
while ( *pszDrive != NULL ) { uiType = GetDriveType( pszDrive );
CharUpper( pszDrive ); idx = pszDrive[ 0 ] - 'A';
hr = THR( StringCchCopyW( m_rgdluDrives[ idx ].szDrive, ARRAYSIZE( m_rgdluDrives[ idx ].szDrive ), pszDrive ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
m_rgdluDrives[ idx ].edluUsage = (EDriveLetterUsage) uiType;
pszDrive += 4; } // while:
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrComputeDriveLetterUsage
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrComputeSystemDriveLetterUsage
//
// Description:
// Fill the array with the enums that represent the drive letter usage.
//
// Arguments:
//
//
// Return Value:
//
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrComputeSystemDriveLetterUsage( void ) { TraceFunc( "" );
HRESULT hr = S_OK; BSTR bstrBootLogicalDisk = NULL; BSTR bstrSystemDevice = NULL; BSTR bstrSystemLogicalDisk = NULL; int idx;
// hr = THR( HrLoadOperatingSystemInfo( m_picccCallback, m_pIWbemServices, &bstrBootDevice, &bstrSystemDevice ) );
// if ( FAILED( hr ) )
// {
// goto Cleanup;
// } // if:
hr = THR( HrGetSystemDevice( &bstrSystemDevice ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
hr = HrConvertDeviceVolumeToLogicalDisk( bstrSystemDevice, &bstrSystemLogicalDisk ); if ( HRESULT_CODE( hr ) == ERROR_INVALID_FUNCTION ) { //
// system volume is an EFI volume on IA64 and won't have a logical disk anyway...
//
hr = S_OK; } // if:
else if ( hr == S_OK ) { idx = bstrSystemLogicalDisk[ 0 ] - 'A'; m_rgdluDrives[ idx ].edluUsage = dluSYSTEM; } // else if:
if ( FAILED( hr ) ) { THR( hr ); goto Cleanup; } // if:
hr = THR( HrGetBootLogicalDisk( &bstrBootLogicalDisk ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
idx = bstrBootLogicalDisk[ 0 ] - 'A'; m_rgdluDrives[ idx ].edluUsage = dluSYSTEM;
Cleanup:
TraceSysFreeString( bstrBootLogicalDisk ); TraceSysFreeString( bstrSystemDevice ); TraceSysFreeString( bstrSystemLogicalDisk );
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrComputeSystemDriveLetterUsage
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrSetPageFileEnumIndex
//
// Description:
// Mark the drives that have paging files on them.
//
// Arguments:
//
//
// Return Value:
// S_OK
// Success.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrSetPageFileEnumIndex( void ) { TraceFunc( "" );
HRESULT hr = S_OK; WCHAR szLogicalDisks[ 26 ]; int cLogicalDisks = 0; int idx; int idxDrive;
hr = THR( HrGetPageFileLogicalDisks( m_picccCallback, m_pIWbemServices, szLogicalDisks, &cLogicalDisks ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
for ( idx = 0; idx < cLogicalDisks; idx++ ) { idxDrive = szLogicalDisks[ idx ] - L'A'; m_rgdluDrives[ idxDrive ].edluUsage = dluSYSTEM; } // for:
Cleanup:
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrSetPageFileEnumIndex
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrSetCrashDumpEnumIndex
//
// Description:
// Mark the drive that has a crash dump file on it.
//
// Arguments:
//
//
// Return Value:
// S_OK
// Success.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrSetCrashDumpEnumIndex( void ) { TraceFunc( "" );
HRESULT hr = S_OK; BSTR bstrCrashDumpDrive = NULL; int idx;
hr = THR( HrGetCrashDumpLogicalDisk( &bstrCrashDumpDrive ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
idx = bstrCrashDumpDrive[ 0 ] - L'A'; m_rgdluDrives[ idx ].edluUsage = dluSYSTEM;
Cleanup:
TraceSysFreeString( bstrCrashDumpDrive );
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrSetCrashDumpEnumIndex
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrGetVolumeInfo
//
// Description:
// Gather the volume info for the drive letters that we have already
// have loaded. We need the drive letter info to promote those drives
// from their basic type to a system type if there are on the same SCSI
// bus and port as one of the five kinds of system disks.
//
// Arguments:
// None.
//
// Return Value:
// S_OK
// Success.
//
// Remarks:
// If any if the IOCTL wrapper functions fail then that drive letter will
// simply not be able to be promoted to a system disk. This is not a big
// deal and it's okay to skip gathering the data for those disks.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrGetVolumeInfo( void ) { TraceFunc( "" );
HRESULT hr = S_OK; int idxDriveLetter; WCHAR szDevice[ 7 ]; DWORD sc; HANDLE hVolume = INVALID_HANDLE_VALUE; VOLUME_DISK_EXTENTS * pvde = NULL; DWORD cbvde = 0; SCSI_ADDRESS saAddress; SSCSIInfo * psi = NULL;
//
// Initialize the disk extents buffer. This will be re-allocated and re-used.
//
cbvde = sizeof( VOLUME_DISK_EXTENTS ); pvde = (PVOLUME_DISK_EXTENTS) TraceAlloc( 0, cbvde ); if ( pvde == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if:
//
// Loop through each drive letter.
//
for ( idxDriveLetter = 0; idxDriveLetter < 26; idxDriveLetter++ ) { //
// Cleanup.
//
if ( hVolume != INVALID_HANDLE_VALUE ) { CloseHandle( hVolume ); hVolume = INVALID_HANDLE_VALUE; } // if:
//
// Only need to check where we actually have a drive letter that could be on a system bus.
//
if ( ( m_rgdluDrives[ idxDriveLetter ].edluUsage == dluUNKNOWN ) || ( m_rgdluDrives[ idxDriveLetter ].edluUsage == dluNETWORK_DRIVE ) || ( m_rgdluDrives[ idxDriveLetter ].edluUsage == dluRAM_DISK ) ) { continue; } // if:
hr = THR( StringCchPrintfW( szDevice, ARRAYSIZE( szDevice ), L"\\\\.\\%c:", m_rgdluDrives[ idxDriveLetter ].szDrive[ 0 ] ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// Get handle to the disk
//
hVolume = CreateFileW( szDevice, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hVolume == INVALID_HANDLE_VALUE ) { //
// Log the problem and continue. Make the HRESULT a warning
// HRESULT since we don't want an [ERR] showing up in the log
// file.
//
sc = TW32( GetLastError() ); hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc ); LOG_STATUS_REPORT_STRING( L"Could not create a handle to drive \"%1!ws!\". Ignoring and device will be skipped.", m_rgdluDrives[ idxDriveLetter ].szDrive, hr ); continue; } // if:
sc = TW32E( ScGetDiskExtents( hVolume, &pvde, &cbvde ), ERROR_INVALID_FUNCTION ); switch ( sc ) { //
// The volume at the drive letter is not a volume and it may simply be a disk. See if we can get any SCSI address info...
//
case ERROR_INVALID_FUNCTION: { //
// If we got the address info then we need to save if off with the drive letter usage struct.
//
sc = ScGetSCSIAddressInfo( hVolume, &saAddress ); if ( sc == ERROR_SUCCESS ) { psi = (SSCSIInfo *) TraceAlloc( 0, sizeof( SSCSIInfo ) * 1 ); if ( psi == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if:
psi->uiSCSIPort = saAddress.PortNumber; psi->uiSCSIBus = saAddress.PathId;
m_rgdluDrives[ idxDriveLetter ].cDisks = 1; m_rgdluDrives[ idxDriveLetter ].psiInfo = psi; psi =NULL; } // if:
else { //
// Log the problem and continue. Make the HRESULT a
// warning HRESULT since we don't want an [ERR]
// showing up in the log file.
//
hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc ); LOG_STATUS_REPORT_STRING( L"Could not get the SCSI address for drive \"%1!ws!\". Ignoring and skipping this device.", m_rgdluDrives[ idxDriveLetter ].szDrive, hr ); } // else:
break; } // case: ERROR_INVALID_FUNCTION
//
// The volume at the drive letter may be an multi disk volume so we have to process all of the disks...
//
case ERROR_SUCCESS: { DWORD idxExtent; HANDLE hDisk = INVALID_HANDLE_VALUE; STORAGE_DEVICE_NUMBER sdn; BOOL fOpenNewDevice = TRUE; BOOL fRetainSCSIInfo = TRUE; WCHAR sz[ _MAX_PATH ];
//
// Allocate enough structs to hold the scsi address info for this volume.
//
psi = (SSCSIInfo *) TraceAlloc( 0, sizeof( SSCSIInfo ) * pvde->NumberOfDiskExtents ); if ( psi == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if:
//
// Get the device number for the device that we have open. If it is not the same as the current device from the
// drive extents that we are working on then we need to open another device. When working with a basic disk the
// volume that we already have open is the one disk and we can just use it. If we are using a multi disk volume
// then we have to open each disk in turn.
//
sc = ScGetStorageDeviceNumber( hVolume, &sdn ); if ( sc == ERROR_SUCCESS ) { if ( ( pvde->NumberOfDiskExtents == 1 ) && ( pvde->Extents[ 0 ].DiskNumber == sdn.DeviceNumber ) ) { fOpenNewDevice = FALSE; } // if:
} // if:
for ( idxExtent = 0; idxExtent < pvde->NumberOfDiskExtents; idxExtent++ ) { if ( fOpenNewDevice ) { hr = THR( StringCchPrintfW( sz, ARRAYSIZE( sz ), g_szPhysicalDriveFormat, pvde->Extents[ idxExtent ].DiskNumber ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
hDisk = CreateFileW( sz, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hDisk == INVALID_HANDLE_VALUE ) { //
// Log the problem and continue. Make the HRESULT
// a warning HRESULT since we don't want an [ERR]
// showing up in the log file.
//
sc = TW32( GetLastError() ); hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc ); LOG_STATUS_REPORT_STRING( L"Could not create a handle to drive \"%1!ws!\". Ignoring and skipping device.", sz, hr ); continue; } // if:
} // if:
sc = TW32( ScGetSCSIAddressInfo( fOpenNewDevice ? hDisk : hVolume, &saAddress ) ); if ( sc == ERROR_SUCCESS ) { psi[ idxExtent ].uiSCSIPort = saAddress.PortNumber; psi[ idxExtent ].uiSCSIBus = saAddress.PathId;
if ( hDisk != INVALID_HANDLE_VALUE ) { VERIFY( CloseHandle( hDisk ) ); hDisk = INVALID_HANDLE_VALUE; } // if:
} // if:
else { //
// Having a multi-device volume that doesn't support
// getting SCSI information seems like an unlikely
// situation.
//
Assert( pvde->NumberOfDiskExtents == 1 );
//
// Log the problem and continue. Make the HRESULT a warning
// HRESULT since we don't want an [ERR] showing up in the log
// file.
//
// An example of a volume that might cause this is a
// USB memory stick.
//
hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc ); LOG_STATUS_REPORT_STRING( L"Could not get the SCSI address for drive \"%1!ws!\". Ignoring and skipping this device.", m_rgdluDrives[ idxDriveLetter ].szDrive, hr );
//
// Tell the block of code below to free the already
// allocated SCSI info. Let's also leave now...
//
fRetainSCSIInfo = FALSE; break; } // else:
} // for: each extent
//
// Should we keep the SCSI information from above?
//
if ( fRetainSCSIInfo ) { m_rgdluDrives[ idxDriveLetter ].cDisks = pvde->NumberOfDiskExtents; m_rgdluDrives[ idxDriveLetter ].psiInfo = psi; psi = NULL; } // if: save the SCSI info...
else { //
// Zero out this data for safety. This information is
// processed later and I want to ensure that code does
// not try to process the SCSI info that we could not
// get for this/these extents.
//
m_rgdluDrives[ idxDriveLetter ].cDisks = 0; m_rgdluDrives[ idxDriveLetter ].psiInfo = NULL;
TraceFree( psi ); psi = NULL; } // else: do not save the SCSI info...
break; } // case: ERROR_SUCCESS
default: //
// Log the problem and continue. Make the HRESULT a warning
// HRESULT since we don't want an [ERR] showing up in the log
// file.
//
hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc ); LOG_STATUS_REPORT_STRING( L"Could not get the drive extents of drive \"%1!ws!\". Ignoring and skipping device.", m_rgdluDrives[ idxDriveLetter ].szDrive, hr ); break; } // switch: sc from ScGetDiskExtents()
} // for: each drive letter
//
// If we didn't go to cleanup then whatever status may be in hr is no longer interesting and we
// should return S_OK to the caller.
//
hr = S_OK;
Cleanup:
TraceFree( psi ); TraceFree( pvde );
if ( hVolume != INVALID_HANDLE_VALUE ) { VERIFY( CloseHandle( hVolume ) ); } // if:
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrGetVolumeInfo
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::ScGetDiskExtents
//
// Description:
// Get the volume extents info.
//
// Arguments:
// hVolumeIn
// The volume to get the extents for.
//
// ppvdeInout
// Buffer that holds the disk extents.
//
// pcbvdeInout
// Size of the buffer that holds the disk extents.
//
// Return Value:
// ERROR_SUCCESS
// Success.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD CClusCfgNodeInfo::ScGetDiskExtents( HANDLE hVolumeIn , VOLUME_DISK_EXTENTS ** ppvdeInout , DWORD * pcbvdeInout ) { TraceFunc( "" ); Assert( hVolumeIn != INVALID_HANDLE_VALUE ); Assert( ppvdeInout != NULL ); Assert( pcbvdeInout != NULL );
DWORD sc = ERROR_SUCCESS; DWORD cbSize; int cTemp; BOOL fRet; PVOLUME_DISK_EXTENTS pvdeTemp = NULL;
//
// Since this buffer is re-used it should be cleaned up.
//
ZeroMemory( *ppvdeInout, *pcbvdeInout );
for ( cTemp = 0; cTemp < 2; cTemp++ ) { fRet = DeviceIoControl( hVolumeIn , IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS , NULL , 0 , *ppvdeInout , *pcbvdeInout , &cbSize , FALSE ); if ( fRet == FALSE ) { sc = GetLastError(); if ( sc == ERROR_MORE_DATA ) { *pcbvdeInout = sizeof( VOLUME_DISK_EXTENTS ) + ( sizeof( DISK_EXTENT ) * (*ppvdeInout)->NumberOfDiskExtents );
pvdeTemp = (PVOLUME_DISK_EXTENTS) TraceReAlloc( *ppvdeInout, *pcbvdeInout, HEAP_ZERO_MEMORY ); if ( pvdeTemp == NULL ) { sc = TW32( ERROR_OUTOFMEMORY ); break; } // if:
*ppvdeInout = pvdeTemp; continue; } // if:
else { break; } // else:
} // if:
else { sc = ERROR_SUCCESS; break; } // else:
} // for:
//
// Shouldn't go through the loop more than twice!
//
Assert( cTemp != 2 );
HRETURN( sc );
} //*** CClusCfgNodeInfo::ScGetDiskExtents
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::ScGetSCSIAddressInfo
//
// Description:
// Get the SCSI info for the passed in drive.
//
// Arguments:
// hDiskIn
// The "disk" to send the IOCTL to.
//
// psaAddressOut
// The SCSI address info.
//
// Return Value:
// S_OK
// Success.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD CClusCfgNodeInfo::ScGetSCSIAddressInfo( HANDLE hDiskIn , SCSI_ADDRESS * psaAddressOut ) { TraceFunc( "" ); Assert( hDiskIn != INVALID_HANDLE_VALUE ); Assert( psaAddressOut != NULL );
DWORD sc = ERROR_SUCCESS; BOOL fRet; DWORD cb;
ZeroMemory( psaAddressOut, sizeof( *psaAddressOut ) );
fRet = DeviceIoControl( hDiskIn , IOCTL_SCSI_GET_ADDRESS , NULL , 0 , psaAddressOut , sizeof( *psaAddressOut ) , &cb , FALSE ); if ( fRet == FALSE ) { //
// Not all devices support this IOCTL and they will be skipped by the caller.
// There is no need to make this noisy since a failure is expected.
//
sc = GetLastError(); goto Cleanup; } // if:
Cleanup:
HRETURN( sc );
} //*** CClusCfgNodeInfo::ScGetSCSIAddressInfo
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::ScGetStorageDeviceNumber
//
// Description:
// Get the device number info for the passed in volume.
//
// Arguments:
// hDiskIn
// The "disk" to send the IOCTL to.
//
// psdnOut
// The storage device number.
//
// Return Value:
// S_OK
// Success.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD CClusCfgNodeInfo::ScGetStorageDeviceNumber( HANDLE hDiskIn , STORAGE_DEVICE_NUMBER * psdnOut ) { TraceFunc( "" ); Assert( hDiskIn != INVALID_HANDLE_VALUE ); Assert( psdnOut != NULL );
DWORD sc = ERROR_SUCCESS; BOOL fRet; DWORD cb;
ZeroMemory( psdnOut, sizeof( *psdnOut ) );
fRet = DeviceIoControl( hDiskIn , IOCTL_STORAGE_GET_DEVICE_NUMBER , NULL , 0 , psdnOut , sizeof( *psdnOut ) , &cb , FALSE ); if ( fRet == FALSE ) { sc = GetLastError(); goto Cleanup; } // if:
Cleanup:
HRETURN( sc );
} //*** CClusCfgNodeInfo::ScGetStorageDeviceNumber
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusCfgNodeInfo::HrUpdateSystemBusDrives
//
// Description:
// Find all the "SYSTEM" drives and mark any other disks on those drives
// as "??? on system bus".
//
// Arguments:
// None.
//
// Return Value:
// S_OK
// Success.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CClusCfgNodeInfo::HrUpdateSystemBusDrives( void ) { TraceFunc( "" );
HRESULT hr = S_OK; int idxOuter; // the index of the drives in m_rgdluDrives
int idxInner; // the index of the drives that we are scanning
DWORD idxOuterExtents; DWORD idxInnerExtents; UINT uiSCSIPort; UINT uiSCSIBus;
//
// Loop through each drive letter looking for those that are "system".
//
for ( idxOuter = 0; idxOuter < 26; idxOuter++ ) { //
// We only need to worry about system disks.
//
if ( m_rgdluDrives[ idxOuter ].edluUsage != dluSYSTEM ) { continue; } // if:
//
// Loop through the the "extents" records which contain the bus and port info for each disk in that volume.
//
for ( idxOuterExtents = 0; idxOuterExtents < m_rgdluDrives[ idxOuter ].cDisks; idxOuterExtents++ ) { uiSCSIPort = m_rgdluDrives[ idxOuter ].psiInfo[ idxOuterExtents ].uiSCSIPort; uiSCSIBus = m_rgdluDrives[ idxOuter ].psiInfo[ idxOuterExtents ].uiSCSIBus;
//
// Loop through the drives again to find those that are on the same bus and port as the
// disk at idxOuter.
//
for ( idxInner = 0; idxInner < 26; idxInner++ ) { //
// Skip the index that we are checking. May need to skip any other disks that are
// still marked dluSYSTEM?
//
// Skip any indexes that don't have a drive...
//
if ( ( idxInner == idxOuter ) || ( m_rgdluDrives[ idxInner ].edluUsage == dluUNKNOWN ) ) { continue; } // if:
//
// Loop through the port and bus info for the drives on the volume at idxInner.
//
for ( idxInnerExtents = 0; idxInnerExtents < m_rgdluDrives[ idxInner ].cDisks; idxInnerExtents++ ) { if ( ( uiSCSIPort == m_rgdluDrives[ idxInner ].psiInfo[ idxInnerExtents ].uiSCSIPort ) && ( uiSCSIBus == m_rgdluDrives[ idxInner ].psiInfo[ idxInnerExtents ].uiSCSIBus ) ) { //
// Promote the usage enum to reflect that it is on the system bus.
//
// BTW: += does not work for enums!
//
m_rgdluDrives[ idxInner ].edluUsage = (EDriveLetterUsage)( m_rgdluDrives[ idxInner ].edluUsage + dluSTART_OF_SYSTEM_BUS );
//
// If any drive in the volume is on a system bus and port then we are done.
//
break; } // if:
} // for: each inner extent
} // for: each inner drive letter
} // for: each outer extent
} // for: each outer drive letter
HRETURN( hr );
} //*** CClusCfgNodeInfo::HrUpdateSystemBusDrives
|