//////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2000-2001 Microsoft Corporation
//
//  Module Name:
//      CEnumPhysicalDisks.cpp
//
//  Description:
//      This file contains the definition of the CEnumPhysicalDisks
//       class.
//
//      The class CEnumPhysicalDisks is the enumeration of cluster
//      storage devices. It implements the IEnumClusCfgManagedResources
//      interface.
//
//  Documentation:
//
//  Header File:
//      CEnumPhysicalDisks.h
//
//  Maintained By:
//      Galen Barbee (GalenB) 23-FEB-2000
//
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
#include "pch.h"
#include "CEnumPhysicalDisks.h"
#include "CPhysicalDisk.h"
#include <PropList.h>


//////////////////////////////////////////////////////////////////////////////
// Constant Definitions
//////////////////////////////////////////////////////////////////////////////

DEFINE_THISCLASS( "CEnumPhysicalDisks" );


//*************************************************************************//


/////////////////////////////////////////////////////////////////////////////
// CEnumPhysicalDisks class
/////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::S_HrCreateInstance
//
//  Description:
//      Create a CEnumPhysicalDisks instance.
//
//  Arguments:
//      None.
//
//  Return Values:
//      S_OK
//          Success.
//
//      E_POINTER
//          The passed in ppunk is NULL.
//
//      other HRESULTs
//          Object creation failed.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::S_HrCreateInstance( IUnknown ** ppunkOut )
{
    TraceFunc( "" );

    HRESULT                 hr;
    CEnumPhysicalDisks *    pccpd = NULL;

    if ( ppunkOut == NULL )
    {
        hr = THR( E_POINTER );
        goto Cleanup;
    } // if:

    pccpd = new CEnumPhysicalDisks();
    if ( pccpd == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
        goto Cleanup;
    } // if: error allocating object

    hr = THR( pccpd->HrInit() );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if: HrInit() failed

    hr = THR( pccpd->TypeSafeQI( IUnknown, ppunkOut ) );

Cleanup:

    if ( FAILED( hr ) )
    {
        LogMsg( L"[SRV] CEnumPhysicalDisks::S_HrCreateInstance() failed. (hr = %#08x)", hr );
    } // if:

    if ( pccpd != NULL )
    {
        pccpd->Release();
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::S_HrCreateInstance


//////////////////////////////////////////////////////////////////////////////
//++
//
//  IUnknown *
//  CEnumPhysicalDisks::S_RegisterCatIDSupport
//
//  Description:
//      Registers/unregisters this class with the categories that it belongs
//      to.
//
//  Arguments:
//      IN  ICatRegister * picrIn
//          Used to register/unregister our CATID support.
//
//      IN  BOOL fCreateIn
//          When true we are registering the server.  When false we are
//          un-registering the server.
//
//  Return Values:
//      S_OK
//          Success.
//
//      E_INVALIDARG
//          The passed in ICatRgister pointer was NULL.
//
//      other HRESULTs
//          Registration/Unregistration failed.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::S_RegisterCatIDSupport(
    ICatRegister *  picrIn,
    BOOL            fCreateIn
    )
{
    TraceFunc( "" );

    HRESULT hr = S_OK;
    CATID   rgCatIds[ 1 ];

    if ( picrIn == NULL )
    {
        hr = THR( E_INVALIDARG );
        goto Cleanup;
    } // if:

    rgCatIds[ 0 ] = CATID_EnumClusCfgManagedResources;

    if ( fCreateIn )
    {
        hr = THR( picrIn->RegisterClassImplCategories( CLSID_EnumPhysicalDisks, 1, rgCatIds ) );
    } // if:

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::S_RegisterCatIDSupport


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::CEnumPhysicalDisks
//
//  Description:
//      Constructor of the CEnumPhysicalDisks 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.
//
//--
//////////////////////////////////////////////////////////////////////////////
CEnumPhysicalDisks::CEnumPhysicalDisks( void )
    : m_cRef( 1 )
    , m_lcid( LOCALE_NEUTRAL )
    , m_fLoadedDevices( false )
{
    TraceFunc( "" );

    // Increment the count of components in memory so the DLL hosting this
    // object cannot be unloaded.
    InterlockedIncrement( &g_cObjects );

    Assert( m_picccCallback == NULL );
    Assert( m_pIWbemServices == NULL );
    Assert( m_prgDisks == NULL );
    Assert( m_idxNext == 0 );
    Assert( m_idxEnumNext == 0 );
    Assert( m_bstrNodeName == NULL );
    Assert( m_bstrBootDevice == NULL );
    Assert( m_bstrSystemDevice == NULL );
    Assert( m_bstrBootLogicalDisk == NULL );
    Assert( m_bstrSystemLogicalDisk == NULL );
    Assert( m_bstrSystemWMIDeviceID == NULL );
    Assert( m_cDiskCount == 0 );

    TraceFuncExit();

} //*** CEnumPhysicalDisks::CEnumPhysicalDisks


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::~CEnumPhysicalDisks
//
//  Description:
//      Desstructor of the CEnumPhysicalDisks class.
//
//  Arguments:
//      None.
//
//  Return Value:
//      None.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CEnumPhysicalDisks::~CEnumPhysicalDisks( void )
{
    TraceFunc( "" );

    ULONG   idx;

    if ( m_pIWbemServices != NULL )
    {
        m_pIWbemServices->Release();
    } // if:

    if ( m_picccCallback != NULL )
    {
        m_picccCallback->Release();
    } // if:

    for ( idx = 0; idx < m_idxNext; idx++ )
    {
        if ( (*m_prgDisks)[ idx ] != NULL )
        {
            ((*m_prgDisks)[ idx ])->Release();
        } // end if:
    } // for:

    TraceFree( m_prgDisks );

    TraceSysFreeString( m_bstrNodeName );
    TraceSysFreeString( m_bstrBootDevice );
    TraceSysFreeString( m_bstrSystemDevice );
    TraceSysFreeString( m_bstrBootLogicalDisk );
    TraceSysFreeString( m_bstrSystemLogicalDisk );
    TraceSysFreeString( m_bstrSystemWMIDeviceID );

    // There's going to be one less component in memory. Decrement component count.
    InterlockedDecrement( &g_cObjects );

    TraceFuncExit();

} //*** CEnumPhysicalDisks::~CEnumPhysicalDisks


//*************************************************************************//


/////////////////////////////////////////////////////////////////////////////
// CEnumPhysicalDisks -- IUnknown interface.
/////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//++
//
//  STDMETHODIMP_( ULONG )
//  CEnumPhysicalDisks:: [IUNKNOWN] AddRef
//
//  Description:
//      Increment the reference count of this object by one.
//
//  Arguments:
//      None.
//
//  Return Value:
//      The new reference count.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG )
CEnumPhysicalDisks::AddRef( void )
{
    TraceFunc( "[IUnknown]" );

    InterlockedIncrement( & m_cRef );

    RETURN(  m_cRef );

} //*** CEnumPhysicalDisks::AddRef


//////////////////////////////////////////////////////////////////////////////
//++
//
//  STDMETHODIMP_( ULONG )
//  CEnumPhysicalDisks:: [IUNKNOWN] Release
//
//  Description:
//      Decrement the reference count of this object by one.
//
//  Arguments:
//      None.
//
//  Return Value:
//      The new reference count.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG )
CEnumPhysicalDisks::Release( void )
{
    TraceFunc( "[IUnknown]" );

    LONG    cRef;

    cRef = InterlockedDecrement( &m_cRef );
    if ( cRef == 0 )
    {
        TraceDo( delete this );
    } // if: reference count equal to zero

    RETURN( cRef );

} //*** CEnumPhysicalDisks::Release


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:: [INKNOWN] QueryInterface
//
//  Description:
//      Query this object for the passed in interface.
//
//  Arguments:
//      IN  REFIID  riid,
//          Id of interface requested.
//
//      OUT void ** ppv
//          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.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::QueryInterface( REFIID  riid, void ** ppv )
{
    TraceQIFunc( riid, ppv );

    HRESULT hr = E_NOINTERFACE;

    if ( IsEqualIID( riid, IID_IUnknown ) )
    {
         *ppv = static_cast< IEnumClusCfgManagedResources * >( this );
         hr = S_OK;
    } // if: IUnknown
    else if ( IsEqualIID( riid, IID_IEnumClusCfgManagedResources ) )
    {
        *ppv = TraceInterface( __THISCLASS__, IEnumClusCfgManagedResources, this, 0 );
        hr   = S_OK;
    } // else if:
    else if ( IsEqualIID( riid, IID_IClusCfgWbemServices ) )
    {
        *ppv = TraceInterface( __THISCLASS__, IClusCfgWbemServices, this, 0 );
        hr   = S_OK;
    } // else if:
    else if ( IsEqualIID( riid, IID_IClusCfgInitialize ) )
    {
        *ppv = TraceInterface( __THISCLASS__, IClusCfgInitialize, this, 0 );
        hr   = S_OK;
    } // else if:

    if ( SUCCEEDED( hr ) )
    {
        ((IUnknown *) *ppv)->AddRef( );
    } // if: success

     QIRETURN_IGNORESTDMARSHALLING( hr, riid );

} //*** CEnumPhysicalDisks::QueryInterface


//*************************************************************************//


/////////////////////////////////////////////////////////////////////////////
// CEnumPhysicalDisks -- IClusCfgWbemServices interface.
/////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::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
CEnumPhysicalDisks::SetWbemServices( IWbemServices * pIWbemServicesIn )
{
    TraceFunc( "[IClusCfgWbemServices]" );

    HRESULT hr = S_OK;

    if ( pIWbemServicesIn == NULL )
    {
        hr = THR( E_POINTER );
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_SetWbemServices_Enum_PhysDisk, IDS_ERROR_NULL_POINTER, hr );
        goto Cleanup;
    } // if:

    m_pIWbemServices = pIWbemServicesIn;
    m_pIWbemServices->AddRef();

    hr = THR( HrGetSystemDevice( &m_bstrSystemDevice ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrConvertDeviceVolumeToLogicalDisk( m_bstrSystemDevice, &m_bstrSystemLogicalDisk ) );
    //
    //  system volume is an EFI volume on IA64 and won't have a logical disk.
    //
    if ( HRESULT_CODE( hr ) == ERROR_INVALID_FUNCTION )
    {
        hr = THR( HrConvertDeviceVolumeToWMIDeviceID( m_bstrSystemDevice, &m_bstrSystemWMIDeviceID ) );
        Assert( m_bstrSystemLogicalDisk == NULL );
        Assert( m_bstrSystemWMIDeviceID != NULL );
    } // if:

    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrGetBootLogicalDisk( &m_bstrBootLogicalDisk ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = STHR( HrIsLogicalDiskNTFS( m_bstrBootLogicalDisk ) );
    if ( hr == S_FALSE )
    {
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Boot_Partition_Not_NTFS, IDS_WARNING_BOOT_PARTITION_NOT_NTFS, hr );
        hr = S_OK;
    } // if:

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::SetWbemServices


//*************************************************************************//


/////////////////////////////////////////////////////////////////////////////
// CEnumPhysicalDisks -- IClusCfgInitialize interface.
/////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::Initialize
//
//  Description:
//      Initialize this component.
//
//  Arguments:
//    IN  IUknown * punkCallbackIn
//
//    IN  LCID      lcidIn
//
//  Return Value:
//      S_OK
//          Success
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::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 ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrGetComputerName( ComputerNameNetBIOS, &m_bstrNodeName ) );

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::Initialize


//*************************************************************************//


/////////////////////////////////////////////////////////////////////////////
// CEnumPhysicalDisks -- IEnumClusCfgManagedResources interface.
/////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::Next
//
//  Description:
//
//  Arguments:
//
//  Return Value:
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::Next(
    ULONG                           cNumberRequestedIn,
    IClusCfgManagedResourceInfo **  rgpManagedResourceInfoOut,
    ULONG *                         pcNumberFetchedOut
    )
{
    TraceFunc( "[IEnumClusCfgManagedResources]" );

    HRESULT                         hr = S_FALSE;
    ULONG                           cFetched = 0;
    IClusCfgManagedResourceInfo *   pccsdi;
    IUnknown *                      punk;
    ULONG                           ulStop;

    if ( rgpManagedResourceInfoOut == NULL )
    {
        hr = THR( E_POINTER );
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Next_Enum_PhysDisk, IDS_ERROR_NULL_POINTER, hr );
        goto Cleanup;
    } // if:

    if ( !m_fLoadedDevices )
    {
        hr = THR( HrLoadEnum() );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:
    } // if:

    ulStop = min( cNumberRequestedIn, ( m_idxNext - m_idxEnumNext ) );

    for ( hr = S_OK; ( cFetched < ulStop ) && ( m_idxEnumNext < m_idxNext ); m_idxEnumNext++ )
    {
        punk = (*m_prgDisks)[ m_idxEnumNext ];
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgManagedResourceInfo, &pccsdi ) );
            if ( FAILED( hr ) )
            {
                break;
            } // if:

            rgpManagedResourceInfoOut[ cFetched++ ] = pccsdi;
        } // if:
    } // for:

    if ( FAILED( hr ) )
    {
        m_idxEnumNext -= cFetched;

        while ( cFetched != 0 )
        {
            (rgpManagedResourceInfoOut[ --cFetched ])->Release();
        } // for:

        goto Cleanup;
    } // if:

    if ( cFetched < cNumberRequestedIn )
    {
        hr = S_FALSE;
    } // if:

Cleanup:

    if ( pcNumberFetchedOut != NULL )
    {
        *pcNumberFetchedOut = cFetched;
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::Next


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::Skip
//
//  Description:
//
//  Arguments:
//
//  Return Value:
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::Skip( ULONG cNumberToSkipIn )
{
    TraceFunc( "[IEnumClusCfgManagedResources]" );

    HRESULT hr = S_OK;

    m_idxEnumNext += cNumberToSkipIn;
    if ( m_idxEnumNext >= m_idxNext )
    {
        m_idxEnumNext = m_idxNext;
        hr = STHR( S_FALSE );
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::Skip


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::Reset
//
//  Description:
//
//  Arguments:
//
//  Return Value:
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::Reset( void )
{
    TraceFunc( "[IEnumClusCfgManagedResources]" );

    m_idxEnumNext = 0;

    HRETURN( S_OK );

} //*** CEnumPhysicalDisks::Reset


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::Clone
//
//  Description:
//
//  Arguments:
//
//  Return Value:
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::Clone(
    IEnumClusCfgManagedResources ** ppEnumClusCfgStorageDevicesOut
    )
{
    TraceFunc( "[IEnumClusCfgManagedResources]" );

    HRESULT hr = S_OK;

    if ( ppEnumClusCfgStorageDevicesOut == NULL )
    {
        hr = THR( E_POINTER );
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Clone_Enum_PhysDisk, IDS_ERROR_NULL_POINTER, hr );
        goto Cleanup;
    } // if:

    hr = THR( E_NOTIMPL );

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::Clone


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::Count
//
//  Description:
//      Return the count of items in the Enum.
//
//  Arguments:
//
//  Return Value:
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CEnumPhysicalDisks::Count( DWORD * pnCountOut )
{
    TraceFunc( "[IEnumClusCfgManagedResources]" );

    HRESULT hr = S_OK;

    if ( pnCountOut == NULL )
    {
        hr = THR( E_POINTER );
        goto Cleanup;
    } // if:

    if ( !m_fLoadedDevices )
    {
        hr = THR( HrLoadEnum() );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:
    } // if:

    *pnCountOut = m_cDiskCount;

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::Count


//*************************************************************************//


/////////////////////////////////////////////////////////////////////////////
// CEnumPhysicalDisks class -- Private Methods.
/////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::HrInit
//
//  Description:
//      Initialize this component.
//
//  Arguments:
//      None.
//
//  Return Value:
//
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrInit( void )
{
    TraceFunc( "" );

    HRESULT hr = S_OK;

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrInit


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::HrGetDisks
//
//  Description:
//
//  Arguments:
//
//
//  Return Value:
//
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrGetDisks( void )
{
    TraceFunc( "" );

    HRESULT                 hr = S_FALSE;
    BSTR                    bstrClass;
    IEnumWbemClassObject *  pDisks = NULL;
    ULONG                   ulReturned;
    IWbemClassObject *      pDisk = NULL;

    bstrClass = TraceSysAllocString( L"Win32_DiskDrive" );
    if ( bstrClass == NULL )
    {
        goto OutOfMemory;
    } // if:

    hr = THR( m_pIWbemServices->CreateInstanceEnum( bstrClass, WBEM_FLAG_SHALLOW, NULL, &pDisks ) );
    if ( FAILED( hr ) )
    {
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_WMI_Phys_Disks_Qry_Failed, IDS_ERROR_WMI_PHYS_DISKS_QRY_FAILED, hr );
        goto Cleanup;
    } // if:

    for ( ; ; )
    {
        hr = pDisks->Next( WBEM_INFINITE, 1, &pDisk, &ulReturned );
        if ( ( hr == S_OK ) && ( ulReturned == 1 ) )
        {
            hr = STHR( HrLogDiskInfo( pDisk ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = STHR( IsDiskSCSI( pDisk ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            if ( hr == S_OK )
            {
                hr = STHR( HrCreateAndAddDiskToArray( pDisk ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:
            } // if:

            pDisk->Release();
            pDisk = NULL;
        } // if:
        else if ( ( hr == S_FALSE ) && ( ulReturned == 0 ) )
        {
            hr = S_OK;
            break;
        } // else if:
        else
        {
            STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_WQL_Disk_Qry_Next_Failed, IDS_ERROR_WQL_QRY_NEXT_FAILED, bstrClass, hr );
            goto Cleanup;
        } // else:
    } // for:

    m_idxEnumNext = 0;
    m_fLoadedDevices = TRUE;

    goto Cleanup;

OutOfMemory:

    hr = THR( E_OUTOFMEMORY );
    STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_HrGetDisks, IDS_ERROR_OUTOFMEMORY, hr );

Cleanup:

    if ( pDisk != NULL )
    {
        pDisk->Release();
    } // if:

    if ( pDisks != NULL )
    {
        pDisks->Release();
    } // if:

    TraceSysFreeString( bstrClass );

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrGetDisks


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::HrCreateAndAddDiskToArray
//
//  Description:
//      Create a IClusCfgStorageDevice object and add the passed in disk to
//      the array of punks that holds the disks.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success
//
//      E_OUTOFMEMORY
//          Couldn't allocate memeory.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrCreateAndAddDiskToArray( IWbemClassObject * pDiskIn )
{
    TraceFunc( "" );

    HRESULT                 hr = S_FALSE;
    IUnknown *              punk = NULL;
    IClusCfgSetWbemObject * piccswo = NULL;
    bool                    fRetainObject = true;


    hr = THR( CPhysicalDisk::S_HrCreateInstance( &punk ) );
    if ( FAILED( hr ) )
    {
        goto Exit;
    } // if:

    punk = TraceInterface( L"CPhysicalDisk", IUnknown, punk, 1 );

    hr = THR( HrSetInitialize( punk, m_picccCallback, m_lcid ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrSetWbemServices( punk, m_pIWbemServices ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( punk->TypeSafeQI( IClusCfgSetWbemObject, &piccswo ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = STHR( piccswo->SetWbemObject( pDiskIn, &fRetainObject ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    if ( fRetainObject )
    {
        hr = THR( HrAddDiskToArray( punk ) );
    } // if:

Cleanup:

    if ( piccswo != NULL )
    {
        piccswo->Release();
    } // if:

    punk->Release();

Exit:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrCreateAndAddDiskToArray


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::HrPruneSystemDisks
//
//  Description:
//      Prune all system disks from the list.  System disks are disks that
//      are booted, are running the OS, or have page files.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success
//
//      E_OUTOFMEMORY
//          Couldn't allocate memeory.
//
//  Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrPruneSystemDisks( void )
{
    TraceFunc( "" );

    HRESULT                             hr = S_OK;
    ULONG                               idx;
    ULONG                               ulSCSIBus;
    ULONG                               ulSCSIPort;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;
    IUnknown *                          punk;
    ULONG                               cRemoved = 0;
    ULONG                               cTemp = 0;
    bool                                fSystemAndBootTheSame = ( m_bstrSystemLogicalDisk != NULL ) ? ( m_bstrBootLogicalDisk[ 0 ] == m_bstrSystemLogicalDisk[ 0 ] ) : false;
    WCHAR                               szPageFileDisks[ 26 ];
    int                                 cPageFileDisks = 0;
    int                                 idxPageFileDisk;
    bool                                fPruneBus = false;


    hr = STHR( HrIsSystemBusManaged() );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    //
    //  If the system bus is not managed then we need to prune the disks on those buses
    //  that contain system, boot, and pagefile disks.
    //
    if ( hr == S_FALSE )
    {
        fPruneBus = true;
    } // if:

    //
    //  Prune the disks on the system buses.  If the system disks are IDE they won't
    //  be in the list.
    //

    //
    //  Find the boot disk
    //
    hr = STHR( HrFindDiskWithLogicalDisk( m_bstrBootLogicalDisk[ 0 ], &idx ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    if ( hr == S_OK )
    {
        //
        //  Should we prune the whole bus, or just the boot disk itself?
        //
        if ( fPruneBus )
        {
            hr = THR( HrGetSCSIInfo( idx, &ulSCSIBus, &ulSCSIPort ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Pruning_Boot_Disk_Bus, IDS_INFO_PRUNING_BOOTDISK_BUS, hr );
            hr = THR( HrPruneDisks( ulSCSIBus, ulSCSIPort, &cTemp, IDS_INFO_BOOTDISK_PRUNED ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            cRemoved += cTemp;
        } // if:
        else
        {
            RemoveDiskFromArray( idx );
            cRemoved++;
        } // else:
    } // if:

    //
    //  Prune the system disk bus if it is not the same as the boot disk bus.
    //
    if ( !fSystemAndBootTheSame )
    {
        if ( m_bstrSystemLogicalDisk != NULL )
        {
            Assert( m_bstrSystemWMIDeviceID == NULL );
            hr = STHR( HrFindDiskWithLogicalDisk( m_bstrSystemLogicalDisk[ 0 ], &idx ) );
        } // if:
        else
        {
            Assert( m_bstrSystemLogicalDisk == NULL );
            hr = STHR( HrFindDiskWithWMIDeviceID( m_bstrSystemWMIDeviceID, &idx ) );
        } // else:

        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:

        if ( hr == S_OK )
        {
            //
            //  Should we prune the whole bus, or just the system disk itself?
            //
            if ( fPruneBus )
            {
                hr = THR( HrGetSCSIInfo( idx, &ulSCSIBus, &ulSCSIPort ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Pruning_System_Disk_Bus, IDS_INFO_PRUNING_SYSTEMDISK_BUS, hr );
                hr = THR( HrPruneDisks( ulSCSIBus, ulSCSIPort, &cTemp, IDS_INFO_SYSTEMDISK_PRUNED ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                cRemoved += cTemp;
            } // if:
            else
            {
                RemoveDiskFromArray( idx );
                cRemoved++;
            } // else:
        } // if:
    } // if:

    //
    //  Prune the bus with disks that have paging files.
    //
    hr = THR( HrGetPageFileLogicalDisks( m_picccCallback, m_pIWbemServices, szPageFileDisks, &cPageFileDisks ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    if ( cPageFileDisks > 0 )
    {
        for ( idxPageFileDisk = 0; idxPageFileDisk < cPageFileDisks; idxPageFileDisk++ )
        {
            hr = STHR( HrFindDiskWithLogicalDisk( szPageFileDisks[ idxPageFileDisk ], &idx ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            if ( hr == S_OK )
            {
                //
                //  Should we prune the whole bus, or just the system disk itself?
                //
                if ( fPruneBus )
                {
                    hr = THR( HrGetSCSIInfo( idx, &ulSCSIBus, &ulSCSIPort ) );
                    if ( FAILED( hr ) )
                    {
                        goto Cleanup;
                    } // if:

                    STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Pruning_PageFile_Disk_Bus, IDS_INFO_PRUNING_PAGEFILEDISK_BUS, hr );
                    hr = THR( HrPruneDisks( ulSCSIBus, ulSCSIPort, &cTemp, IDS_INFO_PAGEFILEDISK_PRUNED ) );
                    if ( FAILED( hr ) )
                    {
                        goto Cleanup;
                    } // if:

                    cRemoved += cTemp;
                } // if:
                else
                {
                    RemoveDiskFromArray( idx );
                    cRemoved++;
                } // else:
            } // if:
        } // for:
    } // if:

    //
    //  Last ditch effort to properly set the managed state of the remaining disks.
    //
    for ( idx = 0; ( cRemoved < m_idxNext ) && ( idx < m_idxNext ); idx++ )
    {
        punk = (*m_prgDisks)[ idx ];                                                        // don't ref
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
            if ( FAILED( hr ) )
            {
                LOG_STATUS_REPORT( L"Could not query for the IClusCfgPhysicalDiskProperties interface.", hr );
                goto Cleanup;
            } // if:

            //
            //  Give the disk a chance to figure out for itself if it should be managed.
            //
            hr = STHR( piccpdp->CanBeManaged() );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            piccpdp->Release();
            piccpdp = NULL;
        } // if:
    } // for:

    //
    //  Minor optimization.  If we removed all of the elements reset the enum next to 0.
    //
    if ( cRemoved == m_idxNext )
    {
        m_idxNext = 0;
    } // if:

    hr = S_OK;

Cleanup:

    if ( piccpdp != NULL )
    {
        piccpdp->Release();
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrPruneSystemDisks


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::IsDiskSCSI
//
//  Description:
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Disk is SCSI.
//
//      S_FALSE
//          Disk is not SCSI.
//
//      E_OUTOFMEMORY
//          Couldn't allocate memeory.
//
//  Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::IsDiskSCSI( IWbemClassObject * pDiskIn )
{
    TraceFunc( "" );
    Assert( pDiskIn != NULL );

    HRESULT hr;
    VARIANT var;

    VariantInit( &var );

    hr = THR( HrGetWMIProperty( pDiskIn, L"InterfaceType", VT_BSTR, &var ) );
    if ( SUCCEEDED( hr ) )
    {
        if ( ( wcscmp( L"SCSI", var.bstrVal ) == 0 ) )
        {
            hr = S_OK;
        } // if:
        else
        {
            hr = S_FALSE;
        } // else:
    } // if:

    VariantClear( &var );

    HRETURN( hr );

} //*** CEnumPhysicalDisks::IsDiskSCSI


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrAddDiskToArray
//
//  Description:
//      Add the passed in disk to the array of punks that holds the disks.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success
//
//      E_OUTOFMEMORY
//          Couldn't allocate memeory.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrAddDiskToArray( IUnknown * punkIn )
{
    TraceFunc( "" );
    Assert( punkIn != NULL );

    HRESULT     hr = S_OK;
    IUnknown *  ((*prgpunks)[]) = NULL;

    prgpunks = (IUnknown *((*)[])) TraceReAlloc( m_prgDisks, sizeof( IUnknown * ) * ( m_idxNext + 1 ), HEAP_ZERO_MEMORY );
    if ( prgpunks == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_HrAddDiskToArray, IDS_ERROR_OUTOFMEMORY, hr );
        goto Cleanup;
    } // if:

    m_prgDisks = prgpunks;

    (*m_prgDisks)[ m_idxNext++ ] = punkIn;
    punkIn->AddRef();
    m_cDiskCount += 1;

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrAddDiskToArray


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrFixupDisks
//
//  Description:
//      Tweak the disks to better reflect how they are managed by this node.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrFixupDisks( void )
{
    TraceFunc( "" );

    HRESULT                         hr;
    ULONG                           idx;
    IUnknown *                      punk = NULL;
    IClusCfgManagedResourceInfo *   piccmri = NULL;

    //
    //  KB: 14-JUN-2000 GalenB
    //
    //  Clear the managed bit on all remaing disks.  These bits will be turned
    //  back on for the disks this node owns.  That happens in
    //  HrNodeResourceCallback().
    //

    //
    //  BUGBUG: 02-MAY-2001 GalenB
    //
    //  Hmmm...  Maybe clearing the managed state from all disks is a mistake.  What if we
    //  have new disks that are not already in the cluster for this clustered node?
    //
    for ( idx = 0; idx < m_idxNext; idx++ )
    {
        punk = (*m_prgDisks)[ idx ];                                                        // don't ref
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgManagedResourceInfo, &piccmri ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = THR( piccmri->SetManaged( false ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            piccmri->Release();
            piccmri = NULL;
        } // if:
    } // for:

    hr = THR( HrEnumNodeResources( m_bstrNodeName ) );

Cleanup:

    if ( piccmri != NULL )
    {
        piccmri->Release();
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrFixupDisks


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrNodeResourceCallback
//
//  Description:
//      Called by CClusterUtils::HrEnumNodeResources() when it finds a
//      resource for this node.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrNodeResourceCallback(
    HCLUSTER    hClusterIn,
    HRESOURCE   hResourceIn
    )
{
    TraceFunc( "" );

    HRESULT                 hr = S_OK;
    CLUS_SCSI_ADDRESS       csa;
    DWORD                   dwSignature;
    BOOL                    fIsQuorum;
    BSTR                    bstrResourceName = NULL;

    hr = STHR( HrIsResourceOfType( hResourceIn, L"Physical Disk" ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    //
    //  If this resource is not a physical disk then we simply want to
    //  skip it.
    //
    if ( hr == S_FALSE )
    {
        goto Cleanup;
    } // if:

    hr = STHR( HrIsCoreResource( hResourceIn ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    fIsQuorum = ( hr == S_OK );

    hr = THR( HrGetClusterDiskInfo( hClusterIn, hResourceIn, &csa, &dwSignature ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrGetClusterProperties( hResourceIn, &bstrResourceName ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrSetThisDiskToBeManaged( csa.TargetId, csa.Lun, fIsQuorum, bstrResourceName, dwSignature ) );

Cleanup:

    TraceSysFreeString( bstrResourceName );

    HRETURN( hr );


} //*** CEnumPhysicalDisks::HrNodeResourceCallback


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrGetClusterDiskInfo
//
//  Description:
//
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrGetClusterDiskInfo(
    HCLUSTER            hClusterIn,
    HRESOURCE           hResourceIn,
    CLUS_SCSI_ADDRESS * pcsaOut,
    DWORD *             pdwSignatureOut
    )
{
    TraceFunc( "" );

    HRESULT                 hr = S_OK;
    DWORD                   sc;
    CClusPropValueList      cpvl;
    CLUSPROP_BUFFER_HELPER  cbhValue = { NULL };

    sc = TW32( cpvl.ScGetResourceValueList( hResourceIn, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO ) );
    if ( sc != ERROR_SUCCESS )
    {
        goto MakeHr;
    } // if:

    sc = TW32( cpvl.ScMoveToFirstValue() );
    if ( sc != ERROR_SUCCESS )
    {
        goto MakeHr;
    } // if:


    for ( ; ; )
    {
        cbhValue = cpvl;

        switch ( cbhValue.pSyntax->dw )
        {
            case CLUSPROP_SYNTAX_PARTITION_INFO :
            {
                break;
            } // case: CLUSPROP_SYNTAX_PARTITION_INFO

            case CLUSPROP_SYNTAX_DISK_SIGNATURE :
            {
                *pdwSignatureOut = cbhValue.pDiskSignatureValue->dw;
                break;
            } // case: CLUSPROP_SYNTAX_DISK_SIGNATURE

            case CLUSPROP_SYNTAX_SCSI_ADDRESS :
            {
                pcsaOut->dw = cbhValue.pScsiAddressValue->dw;
                break;
            } // case: CLUSPROP_SYNTAXscSI_ADDRESS

            case CLUSPROP_SYNTAX_DISK_NUMBER :
            {
                break;
            } // case: CLUSPROP_SYNTAX_DISK_NUMBER

        } // switch:

        sc = cpvl.ScMoveToNextValue();
        if ( sc == ERROR_SUCCESS )
        {
            continue;
        } // if:

        if ( sc == ERROR_NO_MORE_ITEMS )
        {
            break;
        } // if: error occurred moving to the next value

        TW32( sc );
        goto MakeHr;
    } // for:

    goto Cleanup;

MakeHr:

    hr = HRESULT_FROM_WIN32( sc );

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrGetClusterDiskInfo


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrSetThisDiskToBeManaged
//
//  Description:
//
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrSetThisDiskToBeManaged(
      ULONG ulSCSITidIn
    , ULONG ulSCSILunIn
    , BOOL  fIsQuorumIn
    , BSTR  bstrResourceNameIn
    , DWORD dwSignatureIn
    )
{
    TraceFunc( "" );

    HRESULT                             hr = S_OK;
    ULONG                               idx;
    IUnknown *                          punk = NULL;
    IClusCfgManagedResourceInfo *       piccmri = NULL;
    WCHAR                               sz[ 64 ];
    BSTR                                bstrUID = NULL;
    DWORD                               dwSignature;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;

    _snwprintf( sz, ARRAYSIZE( sz ), L"SCSI Tid %ld, SCSI Lun %ld", ulSCSITidIn, ulSCSILunIn );

    //
    //  KB: 15-JUN-2000 GalenB
    //
    //  Find the disk that has the passes in TID and Lun and set it
    //  to be managed.
    //

    for ( idx = 0; idx < m_idxNext; idx++ )
    {
        punk = (*m_prgDisks)[ idx ];                                                        // don't ref
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgManagedResourceInfo, &piccmri ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = THR( piccmri->GetUID( &bstrUID ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            TraceMemoryAddBSTR( bstrUID );

            if ( _wcsicmp( bstrUID, sz ) == 0 )
            {
                hr = THR( piccmri->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                hr = THR( piccpdp->HrGetSignature( &dwSignature ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                hr = THR( piccpdp->HrSetFriendlyName( bstrResourceNameIn ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                piccpdp->Release();
                piccpdp = NULL;

                //
                //  May want to do more with this later...
                //
                Assert( dwSignatureIn == dwSignature );

                hr = THR( piccmri->SetManaged( TRUE ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                hr = THR( piccmri->SetQuorumedDevice( fIsQuorumIn ) );
                if ( FAILED( hr ) )
                {
                    goto Cleanup;
                } // if:

                break;
            } // if:

            TraceSysFreeString( bstrUID );
            bstrUID = NULL;
            piccmri->Release();
            piccmri = NULL;
        } // if:
    } // for:

Cleanup:

    if ( piccpdp != NULL )
    {
        piccpdp->Release();
    } // if:

    if ( piccmri != NULL )
    {
        piccmri->Release();
    } // if:

    TraceSysFreeString( bstrUID );

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrSetThisDiskToBeManaged


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrFindDiskWithLogicalDisk
//
//  Description:
//      Find the disk with the passed in logical disk ID.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.  Found the disk.
//
//      S_FALSE
//          Success.  Did not find the disk.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrFindDiskWithLogicalDisk(
    WCHAR   cLogicalDiskIn,
    ULONG * pidxDiskOut
    )
{
    TraceFunc( "" );
    Assert( pidxDiskOut != NULL );

    HRESULT                             hr = S_OK;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;
    ULONG                               idx;
    bool                                fFoundIt = false;
    IUnknown *                          punk;

    for ( idx = 0; idx < m_idxNext; idx++ )
    {
        punk = (*m_prgDisks)[ idx ];                                                        // don't ref
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = STHR( piccpdp->IsThisLogicalDisk( cLogicalDiskIn ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            if ( hr == S_OK )
            {
                fFoundIt = true;
                break;
            } // if:

            piccpdp->Release();
            piccpdp = NULL;
        } // if:
    } // for:

    if ( !fFoundIt )
    {
        hr = S_FALSE;
    } // if:

    if ( pidxDiskOut != NULL )
    {
        *pidxDiskOut = idx;
    } // if:

Cleanup:

    if ( piccpdp != NULL )
    {
        piccpdp->Release();
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrFindDiskWithLogicalDisk


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrGetSCSIInfo
//
//  Description:
//      Get the SCSI info for the disk at the passed in index.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrGetSCSIInfo(
    ULONG   idxDiskIn,
    ULONG * pulSCSIBusOut,
    ULONG * pulSCSIPortOut
    )
{
    TraceFunc( "" );
    Assert( pulSCSIBusOut != NULL );
    Assert( pulSCSIPortOut != NULL );

    HRESULT                             hr = S_OK;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;

    hr = THR( ((*m_prgDisks)[ idxDiskIn ])->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( piccpdp->HrGetSCSIBus( pulSCSIBusOut ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( piccpdp->HrGetSCSIPort( pulSCSIPortOut ) );

Cleanup:

    if ( piccpdp != NULL )
    {
        piccpdp->Release();
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrGetSCSIInfo


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrPruneDisks
//
//  Description:
//      Get the SCSI info for the disk at the passed in index.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrPruneDisks(
      ULONG     ulSCSIBusIn
    , ULONG     ulSCSIPortIn
    , ULONG *   pulRemovedOut
    , int       nMsgId
    )
{
    TraceFunc( "" );
    Assert( pulRemovedOut != NULL );

    HRESULT                             hr = S_OK;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;
    ULONG                               idx;
    IUnknown *                          punk;
    ULONG                               ulSCSIBus;
    ULONG                               ulSCSIPort;
    ULONG                               cRemoved = 0;

    for ( idx = 0; idx < m_idxNext; idx++ )
    {
        punk = (*m_prgDisks)[ idx ];                                                        // don't ref
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = THR( piccpdp->HrGetSCSIBus( &ulSCSIBus ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = THR( piccpdp->HrGetSCSIPort( &ulSCSIPort ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            if ( ( ulSCSIBusIn == ulSCSIBus ) && ( ulSCSIPortIn == ulSCSIPort ) )
            {
                BSTR                            bstr = NULL;
                IClusCfgManagedResourceInfo *   piccmri = NULL;

                LogPrunedDisk( punk, ulSCSIBusIn, ulSCSIPortIn );

                THR( ((*m_prgDisks)[ idx ])->TypeSafeQI( IClusCfgManagedResourceInfo, &piccmri ) );
                THR( piccmri->GetName( &bstr ) );
                if ( piccmri != NULL )
                {
                    piccmri->Release();
                } // if:

                TraceMemoryAddBSTR( bstr );

                STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_Pruned_Disk_From_Bus, nMsgId, bstr != NULL ? bstr : L"????", hr );
                RemoveDiskFromArray( idx );
                cRemoved++;
                TraceSysFreeString( bstr );
            } // if:

            piccpdp->Release();
            piccpdp = NULL;
        } // if:
    } // for:

    if ( pulRemovedOut != NULL )
    {
        *pulRemovedOut = cRemoved;
    } // if:

Cleanup:

    if ( piccpdp != NULL )
    {
        piccpdp->Release();
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrPruneDisks


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:LogPrunedDisk
//
//  Description:
//      Get the SCSI info for the disk at the passed in index.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CEnumPhysicalDisks::LogPrunedDisk(
    IUnknown *  punkIn,
    ULONG       ulSCSIBusIn,
    ULONG       ulSCSIPortIn
    )
{
    TraceFunc( "" );
    Assert( punkIn != NULL );

    HRESULT                             hr = S_OK;
    IClusCfgManagedResourceInfo *       piccmri = NULL;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;
    BSTR                                bstrName = NULL;
    BSTR                                bstrUID = NULL;
    BSTR                                bstr = NULL;

    hr = THR( punkIn->TypeSafeQI( IClusCfgManagedResourceInfo, &piccmri ) );
    if ( SUCCEEDED( hr ) )
    {
        hr = THR( piccmri->GetUID( &bstrUID ) );
        piccmri->Release();
    } // if:

    if ( FAILED( hr ) )
    {
        bstrUID = TraceSysAllocString( L"<Unknown>" );
    } // if:
    else
    {
        TraceMemoryAddBSTR( bstrUID );
    } // else:

    hr = THR( punkIn->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
    if ( SUCCEEDED( hr ) )
    {
        hr = THR( piccpdp->HrGetDeviceID( &bstrName ) );
        piccpdp->Release();
    } // if:

    if ( FAILED( hr ) )
    {
        bstrName = TraceSysAllocString( L"<Unknown>" );
    } // if:

    hr = THR( HrFormatStringIntoBSTR(
                  L"Pruning SCSI disk '%1!ws!', on Bus '%2!d!' and Port '%3!d!'; at '%4!ws!'"
                , &bstr
                , bstrName
                , ulSCSIBusIn
                , ulSCSIPortIn
                , bstrUID
                ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    LOG_STATUS_REPORT( bstr, hr );

Cleanup:

    TraceSysFreeString( bstrName );
    TraceSysFreeString( bstrUID );
    TraceSysFreeString( bstr );

    TraceFuncExit();

} //*** CEnumPhysicalDisks::LogPrunedDisk


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrIsLogicalDiskNTFS
//
//  Description:
//      Is the passed in logical disk NTFS?
//
//  Arguments:
//      bstrLogicalDiskIn
//
//  Return Value:
//      S_OK
//          The disk is NTFS.
//
//      S_FALSE
//          The disk is not NTFS.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrIsLogicalDiskNTFS( BSTR bstrLogicalDiskIn )
{
    TraceFunc1( "bstrLogicalDiskIn = '%ls'", bstrLogicalDiskIn == NULL ? L"<null>" : bstrLogicalDiskIn );
    Assert( bstrLogicalDiskIn != NULL );

    HRESULT             hr = S_OK;
    IWbemClassObject *  pLogicalDisk = NULL;
    BSTR                bstrPath = NULL;
    WCHAR               sz[ 64 ];
    VARIANT             var;
    size_t              cch;

    VariantInit( &var );

    cch = wcslen( bstrLogicalDiskIn );
    if ( cch > 3 )
    {
        hr = THR( E_INVALIDARG );
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_HrIsLogicalDiskNTFS_InvalidArg, IDS_ERROR_INVALIDARG, hr );
        goto Cleanup;
    } // if:

    //
    //  truncate off any trailing \'s
    //
    if ( bstrLogicalDiskIn[ cch - 1 ] == L'\\' )
    {
        bstrLogicalDiskIn[ cch - 1 ] = '\0';
    } // if:

    //
    //  If we got just the logical disk without the trailing colon...
    //
    if ( wcslen( bstrLogicalDiskIn ) == 1 )
    {
        _snwprintf( sz, ARRAYSIZE( sz ), L"Win32_LogicalDisk.DeviceID=\"%s:\"", bstrLogicalDiskIn );
    } // if:
    else
    {
        _snwprintf( sz, ARRAYSIZE( sz ), L"Win32_LogicalDisk.DeviceID=\"%s\"", bstrLogicalDiskIn );
    } // else:

    bstrPath = TraceSysAllocString( sz );
    if ( bstrPath == NULL )
    {
        hr = THR( E_OUTOFMEMORY );
        STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_HrIsLogicalDiskNTFS, IDS_ERROR_OUTOFMEMORY, hr );
    } // if:

    hr = THR( m_pIWbemServices->GetObject( bstrPath, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pLogicalDisk, NULL ) );
    if ( FAILED( hr ) )
    {
        STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_WMI_Get_LogicalDisk_Failed, IDS_ERROR_WMI_GET_LOGICALDISK_FAILED, bstrLogicalDiskIn, hr );
        goto Cleanup;
    } // if:

    hr = THR( HrGetWMIProperty( pLogicalDisk, L"FileSystem", VT_BSTR, &var ) );
    if (FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    CharUpper( var.bstrVal );

    if ( wcscmp( var.bstrVal, L"NTFS" ) != 0 )
    {
        hr = S_FALSE;
    } // if:

Cleanup:

    if ( pLogicalDisk != NULL )
    {
        pLogicalDisk->Release();
    } // if:

    VariantClear( &var );

    TraceSysFreeString( bstrPath );

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrIsLogicalDiskNTFS


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrLogDiskInfo
//
//  Description:
//      Write the info about this disk into the log.
//
//  Arguments:
//      pDiskIn
//
//  Return Value:
//      S_OK
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrLogDiskInfo( IWbemClassObject * pDiskIn )
{
    TraceFunc( "" );
    Assert( pDiskIn != NULL );

    HRESULT hr = S_OK;
    VARIANT varDeviceID;
    VARIANT varSCSIBus;
    VARIANT varSCSIPort;
    VARIANT varSCSILun;
    VARIANT varSCSITid;
    BSTR    bstr = NULL;

    VariantInit( &varDeviceID );
    VariantInit( &varSCSIBus );
    VariantInit( &varSCSIPort );
    VariantInit( &varSCSILun );
    VariantInit( &varSCSITid );

    hr = THR( HrGetWMIProperty( pDiskIn, L"DeviceID", VT_BSTR, &varDeviceID ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = STHR( IsDiskSCSI( pDiskIn ) );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    //
    // Disk is SCSI...
    //
    if ( hr == S_OK )
    {
        hr = THR( HrGetWMIProperty( pDiskIn, L"SCSIBus", VT_I4, &varSCSIBus ) );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:

        hr = THR( HrGetWMIProperty( pDiskIn, L"SCSITargetId", VT_I4, &varSCSITid ) );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:

        hr = THR( HrGetWMIProperty( pDiskIn, L"SCSILogicalUnit", VT_I4, &varSCSILun ) );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:

        hr = THR( HrGetWMIProperty( pDiskIn, L"SCSIPort", VT_I4, &varSCSIPort ) );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:

        hr = THR( HrFormatStringIntoBSTR(
                      L"Found SCSI disk '%1!ws!' on Bus '%2!d!' and Port '%3!d!'; at TID '%4!d!' and LUN '%5!d!'"
                    , &bstr
                    , varDeviceID.bstrVal
                    , varSCSIBus.iVal
                    , varSCSIPort.iVal
                    , varSCSITid.iVal
                    , varSCSILun.iVal
                    ) );

        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:

        LOG_STATUS_REPORT( bstr, hr );
    } // if:
    else
    {
        STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_Found_Non_SCSI_Disk, IDS_ERROR_FOUND_NON_SCSI_DISK, varDeviceID.bstrVal, hr );
    } // else:

Cleanup:

    VariantClear( &varDeviceID );
    VariantClear( &varSCSIBus );
    VariantClear( &varSCSIPort );
    VariantClear( &varSCSILun );
    VariantClear( &varSCSITid );

    TraceSysFreeString( bstr );

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrLogDiskInfo


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrFindDiskWithWMIDeviceID
//
//  Description:
//      Find the disk with the passed in WMI device ID.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.  Found the disk.
//
//      S_FALSE
//          Success.  Did not find the disk.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrFindDiskWithWMIDeviceID(
    BSTR    bstrWMIDeviceIDIn,
    ULONG * pidxDiskOut
    )
{
    TraceFunc( "" );
    Assert( pidxDiskOut != NULL );

    HRESULT                             hr = S_OK;
    IClusCfgPhysicalDiskProperties *    piccpdp = NULL;
    ULONG                               idx;
    bool                                fFoundIt = false;
    IUnknown *                          punk;
    BSTR                                bstrDeviceID = NULL;

    for ( idx = 0; idx < m_idxNext; idx++ )
    {
        punk = (*m_prgDisks)[ idx ];                                                        // don't ref
        if ( punk != NULL )
        {
            hr = THR( punk->TypeSafeQI( IClusCfgPhysicalDiskProperties, &piccpdp ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            hr = STHR( piccpdp->HrGetDeviceID( &bstrDeviceID ) );
            if ( FAILED( hr ) )
            {
                goto Cleanup;
            } // if:

            if ( wcscmp( bstrWMIDeviceIDIn, bstrDeviceID ) == 0 )
            {
                fFoundIt = true;
                break;
            } // if:

            piccpdp->Release();
            piccpdp = NULL;

            TraceSysFreeString( bstrDeviceID );
            bstrDeviceID = NULL;
        } // if:
    } // for:

    if ( !fFoundIt )
    {
        hr = S_FALSE;
    } // if:

    if ( pidxDiskOut != NULL )
    {
        *pidxDiskOut = idx;
    } // if:

Cleanup:

    if ( piccpdp != NULL )
    {
        piccpdp->Release();
    } // if:

    TraceSysFreeString( bstrDeviceID );

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrFindDiskWithWMIDeviceID


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrIsSystemBusManaged
//
//  Description:
//      Is the system bus managed by the cluster service?
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.  The system bus is managed.
//
//      S_FALSE
//          Success.  The system bus is not managed.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrIsSystemBusManaged( void )
{
    TraceFunc( "" );

    HRESULT hr = S_FALSE;
    DWORD   sc;
    HKEY    hKey = NULL;
    DWORD   dwData;
    DWORD   cbData = sizeof( dwData );

    sc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"SYSTEM\\CURRENTCONTROLSET\\SERVICES\\ClusSvc\\Parameters", 0, KEY_READ, &hKey );
    if ( sc == ERROR_FILE_NOT_FOUND )
    {
        goto Cleanup;       // not yet a cluster node.  Return S_FALSE.
    } // if:

    if ( sc != ERROR_SUCCESS )
    {
        TW32( sc );
        LogMsg( L"[SRV] RegOpenKeyEx() failed. (hr = %#08x)", hr );
        goto Win32Error;
    } // if:

    sc = RegQueryValueEx( hKey, L"ManageDisksOnSystemBuses", NULL, NULL, (LPBYTE) &dwData, &cbData );
    if ( sc == ERROR_FILE_NOT_FOUND )
    {
        goto Cleanup;       // value not found.  Return S_FALSE.
    } // if:

    if ( sc != ERROR_SUCCESS )
    {
        TW32( sc );
        LogMsg( L"[SRV] RegQueryValueEx() failed. (hr = %#08x)", hr );
        goto Win32Error;
    } // if:

    if ( dwData > 0 )
    {
        hr = S_OK;
    } // if:

    goto Cleanup;

Win32Error:

    hr = HRESULT_FROM_WIN32( sc );

Cleanup:

    if ( hKey != NULL )
    {
        RegCloseKey( hKey );
    } // if:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrIsSystemBusManaged


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks:HrGetClusterProperties
//
//  Description:
//      Return the asked for cluster properties.
//
//  Arguments:
//
//
//  Return Value:
//      S_OK
//          Success.
//
//      Win32 Error
//          something failed.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrGetClusterProperties(
      HRESOURCE hResourceIn
    , BSTR *    pbstrResourceNameOut
    )
{
    TraceFunc( "" );
    Assert( pbstrResourceNameOut != NULL );

    HRESULT                 hr = S_OK;
    CClusPropList           cpl;
    CLUSPROP_BUFFER_HELPER  cpbh;
    DWORD                   sc;

    sc = TW32( cpl.ScGetResourceProperties( hResourceIn, CLUSCTL_RESOURCE_GET_RO_COMMON_PROPERTIES ) );
    if ( sc != ERROR_SUCCESS )
    {
        goto MakeHr;
    } // if:

    sc = TW32( cpl.ScMoveToPropertyByName( L"Name" ) );
    if ( sc != ERROR_SUCCESS )
    {
        goto MakeHr;
    } // if:

    cpbh = cpl.CbhCurrentValue();
    Assert( cpbh.pSyntax->dw == CLUSPROP_SYNTAX_LIST_VALUE_SZ );

    if ( ( cpbh.pStringValue->sz != NULL ) && ( wcscmp( cpbh.pStringValue->sz, L"" ) != 0 ) )
    {
        *pbstrResourceNameOut = TraceSysAllocString( cpbh.pStringValue->sz );
        if ( *pbstrResourceNameOut == NULL )
        {
            hr = THR( E_OUTOFMEMORY );
            goto Cleanup;
        } // if:
    } // if:
    else
    {
        hr = THR( E_UNEXPECTED );
        LOG_STATUS_REPORT( L"The name of a physical disk resource was empty!", hr );
    } // else:

    goto Cleanup;

MakeHr:

    hr = HRESULT_FROM_WIN32( sc );

Cleanup:

    HRETURN( hr );

} //*** CEnumPhysicalDisks::HrGetClusterProperties

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::RemoveDiskFromArray
//
//  Description:
//      Release the disk at the specified index in the array and decrease the disk count.
//
//  Arguments:
//      idxDiskIn - the index of the disk to remove; must be less than the array size.
//
//  Return Value:
//      None.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CEnumPhysicalDisks::RemoveDiskFromArray( ULONG idxDiskIn )
{
    TraceFunc( "" );

    Assert( idxDiskIn < m_idxNext );

    ((*m_prgDisks)[ idxDiskIn ])->Release();
    (*m_prgDisks)[ idxDiskIn ] = NULL;

    m_cDiskCount -= 1;

    TraceFuncExit();

} //*** CEnumPhysicalDisks::RemoveDiskFromArray


/////////////////////////////////////////////////////////////////////////////
//++
//
//  CEnumPhysicalDisks::HrLoadEnum
//
//  Description:
//      Load the enum and filter out any devices that don't belong.
//
//  Arguments:
//      None.
//
//  Return Value:
//      S_OK
//          Success.
//
//      Other HRESULT errors.
//
//  Remarks:
//      None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CEnumPhysicalDisks::HrLoadEnum( void )
{
    TraceFunc( "" );

    HRESULT hr = S_OK;

    hr = THR( HrGetDisks() );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = THR( HrPruneSystemDisks() );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    hr = STHR( HrIsNodeClustered() );
    if ( FAILED( hr ) )
    {
        goto Cleanup;
    } // if:

    if ( hr == S_OK )
    {
        hr = THR( HrFixupDisks() );
        if ( FAILED( hr ) )
        {
            goto Cleanup;
        } // if:
    } // if:

    hr = S_OK;  // could have been S_FALSE

Cleanup:

    HRETURN( hr );

} //*** CEnumPysicalDisks::HrLoadEnum