Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2118 lines
56 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CClusCfgNodeInfo.cpp
  7. //
  8. // Description:
  9. // This file contains the definition of the CClusCfgNodeInfo
  10. // class.
  11. //
  12. // The class CClusCfgNodeInfo is the representation of a
  13. // computer that can be a cluster node. It implements the
  14. // IClusCfgNodeInfo interface.
  15. //
  16. // Maintained By:
  17. // Galen Barbee (GalenB) 21-FEB-2000
  18. //
  19. //////////////////////////////////////////////////////////////////////////////
  20. //////////////////////////////////////////////////////////////////////////////
  21. // Include Files
  22. //////////////////////////////////////////////////////////////////////////////
  23. #include "Pch.h"
  24. #include <ClusRTL.h>
  25. #include "CClusCfgNodeInfo.h"
  26. #include "CClusCfgClusterInfo.h"
  27. //////////////////////////////////////////////////////////////////////////////
  28. // Constant Definitions
  29. //////////////////////////////////////////////////////////////////////////////
  30. DEFINE_THISCLASS( "CClusCfgNodeInfo" );
  31. //*************************************************************************//
  32. /////////////////////////////////////////////////////////////////////////////
  33. // CClusCfgNodeInfo class
  34. /////////////////////////////////////////////////////////////////////////////
  35. //////////////////////////////////////////////////////////////////////////////
  36. //++
  37. //
  38. // CClusCfgNodeInfo::S_HrCreateInstance
  39. //
  40. // Description:
  41. // Create a CClusCfgNodeInfo instance.
  42. //
  43. // Arguments:
  44. // None.
  45. //
  46. // Return Values:
  47. // Pointer to CClusCfgNodeInfo instance.
  48. //
  49. //--
  50. //////////////////////////////////////////////////////////////////////////////
  51. HRESULT
  52. CClusCfgNodeInfo::S_HrCreateInstance( IUnknown ** ppunkOut )
  53. {
  54. TraceFunc( "" );
  55. HRESULT hr = S_OK;
  56. CClusCfgNodeInfo * pccni = NULL;
  57. if ( ppunkOut == NULL )
  58. {
  59. hr = THR( E_POINTER );
  60. goto Cleanup;
  61. } // if:
  62. pccni = new CClusCfgNodeInfo();
  63. if ( pccni == NULL )
  64. {
  65. hr = THR( E_OUTOFMEMORY );
  66. goto Cleanup;
  67. } // if: error allocating object
  68. hr = THR( pccni->HrInit() );
  69. if ( FAILED( hr ) )
  70. {
  71. goto Cleanup;
  72. } // if: HrInit() failed
  73. hr = THR( pccni->TypeSafeQI( IUnknown, ppunkOut ) );
  74. if ( FAILED( hr ) )
  75. {
  76. goto Cleanup;
  77. } // if: QI failed
  78. Cleanup:
  79. if ( FAILED( hr ) )
  80. {
  81. LogMsg( L"[SRV] CClusCfgNodeInfo::S_HrCreateInstance() failed. (hr = %#08x)", hr );
  82. } // if:
  83. if ( pccni != NULL )
  84. {
  85. pccni->Release();
  86. } // if:
  87. HRETURN( hr );
  88. } //*** CClusCfgNodeInfo::S_HrCreateInstance
  89. //////////////////////////////////////////////////////////////////////////////
  90. //++
  91. //
  92. // CClusCfgNodeInfo::CClusCfgNodeInfo
  93. //
  94. // Description:
  95. // Constructor of the CClusCfgNodeInfo class. This initializes
  96. // the m_cRef variable to 1 instead of 0 to account of possible
  97. // QueryInterface failure in DllGetClassObject.
  98. //
  99. // Arguments:
  100. // None.
  101. //
  102. // Return Value:
  103. // None.
  104. //
  105. // Remarks:
  106. // None.
  107. //
  108. //--
  109. //////////////////////////////////////////////////////////////////////////////
  110. CClusCfgNodeInfo::CClusCfgNodeInfo( void )
  111. : m_cRef( 1 )
  112. , m_lcid( LOCALE_NEUTRAL )
  113. , m_fIsClusterNode( false )
  114. {
  115. TraceFunc( "" );
  116. // Increment the count of components in memory so the DLL hosting this
  117. // object cannot be unloaded.
  118. InterlockedIncrement( &g_cObjects );
  119. Assert( m_bstrFullDnsName == NULL );
  120. Assert( m_picccCallback == NULL );
  121. Assert( m_pIWbemServices == NULL );
  122. Assert( m_punkClusterInfo == NULL );
  123. Assert( m_cMaxNodes == 0 );
  124. Assert( m_rgdluDrives[ 0 ].edluUsage == dluUNKNOWN );
  125. Assert( m_rgdluDrives[ 0 ].psiInfo == NULL );
  126. TraceFuncExit();
  127. } //*** CClusCfgNodeInfo::CClusCfgNodeInfo
  128. //////////////////////////////////////////////////////////////////////////////
  129. //++
  130. //
  131. // CClusCfgNodeInfo::~CClusCfgNodeInfo
  132. //
  133. // Description:
  134. // Desstructor of the CClusCfgNodeInfo class.
  135. //
  136. // Arguments:
  137. // None.
  138. //
  139. // Return Value:
  140. // None.
  141. //
  142. // Remarks:
  143. // None.
  144. //
  145. //--
  146. //////////////////////////////////////////////////////////////////////////////
  147. CClusCfgNodeInfo::~CClusCfgNodeInfo( void )
  148. {
  149. TraceFunc( "" );
  150. int idx;
  151. TraceSysFreeString( m_bstrFullDnsName );
  152. if ( m_pIWbemServices != NULL )
  153. {
  154. m_pIWbemServices->Release();
  155. } // if:
  156. if ( m_picccCallback != NULL )
  157. {
  158. m_picccCallback->Release();
  159. } // if:
  160. if ( m_punkClusterInfo != NULL )
  161. {
  162. m_punkClusterInfo->Release();
  163. } // if:
  164. for ( idx = 0; idx < 26; idx++ )
  165. {
  166. TraceFree( m_rgdluDrives[ idx ].psiInfo );
  167. } // for:
  168. // There's going to be one less component in memory. Decrement component count.
  169. InterlockedDecrement( &g_cObjects );
  170. TraceFuncExit();
  171. } //*** CClusCfgNodeInfo::~CClusCfgNodeInfo
  172. //*************************************************************************//
  173. /////////////////////////////////////////////////////////////////////////////
  174. // CClusCfgNodeInfo -- IUknkown interface.
  175. /////////////////////////////////////////////////////////////////////////////
  176. //////////////////////////////////////////////////////////////////////////////
  177. //++
  178. //
  179. // CClusCfgNodeInfo::AddRef
  180. //
  181. // Description:
  182. // Increment the reference count of this object by one.
  183. //
  184. // Arguments:
  185. // None.
  186. //
  187. // Return Value:
  188. // The new reference count.
  189. //
  190. // Remarks:
  191. // None.
  192. //
  193. //--
  194. //////////////////////////////////////////////////////////////////////////////
  195. STDMETHODIMP_( ULONG )
  196. CClusCfgNodeInfo::AddRef( void )
  197. {
  198. TraceFunc( "[IUnknown]" );
  199. InterlockedIncrement( & m_cRef );
  200. CRETURN( m_cRef );
  201. } //*** CClusCfgNodeInfo::AddRef
  202. //////////////////////////////////////////////////////////////////////////////
  203. //++
  204. //
  205. // CClusCfgNodeInfo::Release
  206. //
  207. // Description:
  208. // Decrement the reference count of this object by one.
  209. //
  210. // Arguments:
  211. // None.
  212. //
  213. // Return Value:
  214. // The new reference count.
  215. //
  216. // Remarks:
  217. // None.
  218. //
  219. //--
  220. //////////////////////////////////////////////////////////////////////////////
  221. STDMETHODIMP_( ULONG )
  222. CClusCfgNodeInfo::Release( void )
  223. {
  224. TraceFunc( "[IUnknown]" );
  225. LONG cRef;
  226. cRef = InterlockedDecrement( &m_cRef );
  227. if ( cRef == 0 )
  228. {
  229. TraceDo( delete this );
  230. } // if: reference count equal to zero
  231. CRETURN( cRef );
  232. } //*** CClusCfgNodeInfo::Release
  233. //////////////////////////////////////////////////////////////////////////////
  234. //++
  235. //
  236. // CClusCfgNodeInfo::QueryInterface
  237. //
  238. // Description:
  239. // Query this object for the passed in interface.
  240. //
  241. // Arguments:
  242. // riidIn
  243. // Id of interface requested.
  244. //
  245. // ppvOut
  246. // Pointer to the requested interface.
  247. //
  248. // Return Value:
  249. // S_OK
  250. // If the interface is available on this object.
  251. //
  252. // E_NOINTERFACE
  253. // If the interface is not available.
  254. //
  255. // E_POINTER
  256. // ppvOut was NULL.
  257. //
  258. // Remarks:
  259. // None.
  260. //
  261. //--
  262. //////////////////////////////////////////////////////////////////////////////
  263. STDMETHODIMP
  264. CClusCfgNodeInfo::QueryInterface(
  265. REFIID riidIn
  266. , void ** ppvOut
  267. )
  268. {
  269. TraceQIFunc( riidIn, ppvOut );
  270. HRESULT hr = S_OK;
  271. //
  272. // Validate arguments.
  273. //
  274. Assert( ppvOut != NULL );
  275. if ( ppvOut == NULL )
  276. {
  277. hr = THR( E_POINTER );
  278. goto Cleanup;
  279. }
  280. //
  281. // Handle known interfaces.
  282. //
  283. if ( IsEqualIID( riidIn, IID_IUnknown ) )
  284. {
  285. *ppvOut = static_cast< IClusCfgNodeInfo * >( this );
  286. } // if: IUnknown
  287. else if ( IsEqualIID( riidIn, IID_IClusCfgNodeInfo ) )
  288. {
  289. *ppvOut = TraceInterface( __THISCLASS__, IClusCfgNodeInfo, this, 0 );
  290. } // else if: IClusCfgNodeInfo
  291. else if ( IsEqualIID( riidIn, IID_IClusCfgWbemServices ) )
  292. {
  293. *ppvOut = TraceInterface( __THISCLASS__, IClusCfgWbemServices, this, 0 );
  294. } // else if: IClusCfgWbemServices
  295. else if ( IsEqualIID( riidIn, IID_IClusCfgInitialize ) )
  296. {
  297. *ppvOut = TraceInterface( __THISCLASS__, IClusCfgInitialize, this, 0 );
  298. } // else if: IClusCfgInitialize
  299. else
  300. {
  301. *ppvOut = NULL;
  302. hr = E_NOINTERFACE;
  303. }
  304. //
  305. // Add a reference to the interface if successful.
  306. //
  307. if ( SUCCEEDED( hr ) )
  308. {
  309. ((IUnknown *) *ppvOut)->AddRef();
  310. } // if: success
  311. Cleanup:
  312. QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
  313. } //*** CClusCfgNodeInfo::QueryInterface
  314. //*************************************************************************//
  315. /////////////////////////////////////////////////////////////////////////////
  316. // CClusCfgNodeInfo -- IClusCfgWbemServices
  317. // interface.
  318. /////////////////////////////////////////////////////////////////////////////
  319. //////////////////////////////////////////////////////////////////////////////
  320. //++
  321. //
  322. // CClusCfgNodeInfo::SetWbemServices
  323. //
  324. // Description:
  325. // Set the WBEM services provider.
  326. //
  327. // Arguments:
  328. // IN IWbemServices pIWbemServicesIn
  329. //
  330. // Return Value:
  331. // S_OK
  332. // Success
  333. //
  334. // E_POINTER
  335. // The pIWbemServicesIn param is NULL.
  336. //
  337. // Remarks:
  338. // None.
  339. //
  340. //--
  341. //////////////////////////////////////////////////////////////////////////////
  342. STDMETHODIMP
  343. CClusCfgNodeInfo::SetWbemServices( IWbemServices * pIWbemServicesIn )
  344. {
  345. TraceFunc( "[IClusCfgWbemServices]" );
  346. HRESULT hr = S_OK;
  347. if ( pIWbemServicesIn == NULL )
  348. {
  349. hr = THR( E_POINTER );
  350. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_SetWbemServices_Node, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
  351. goto Cleanup;
  352. } // if:
  353. m_pIWbemServices = pIWbemServicesIn;
  354. m_pIWbemServices->AddRef();
  355. Cleanup:
  356. HRETURN( hr );
  357. } //*** CClusCfgNodeInfo::SetWbemServices
  358. //*************************************************************************//
  359. /////////////////////////////////////////////////////////////////////////////
  360. // CClusCfgNodeInfo -- IClusCfgInitialize interface.
  361. /////////////////////////////////////////////////////////////////////////////
  362. //////////////////////////////////////////////////////////////////////////////
  363. //++
  364. //
  365. // CClusCfgNodeInfo::Initialize
  366. //
  367. // Description:
  368. // Initialize this component.
  369. //
  370. // Arguments:
  371. // IN IUknown * punkCallbackIn
  372. //
  373. // IN LCID lcidIn
  374. //
  375. // Return Value:
  376. // S_OK
  377. // Success
  378. //
  379. // Remarks:
  380. // None.
  381. //
  382. //--
  383. //////////////////////////////////////////////////////////////////////////////
  384. STDMETHODIMP
  385. CClusCfgNodeInfo::Initialize(
  386. IUnknown * punkCallbackIn,
  387. LCID lcidIn
  388. )
  389. {
  390. TraceFunc( "[IClusCfgInitialize]" );
  391. Assert( m_picccCallback == NULL );
  392. HRESULT hr = S_OK;
  393. m_lcid = lcidIn;
  394. if ( punkCallbackIn == NULL )
  395. {
  396. hr = THR( E_POINTER );
  397. goto Cleanup;
  398. } // if:
  399. hr = THR( punkCallbackIn->TypeSafeQI( IClusCfgCallback, &m_picccCallback ) );
  400. Cleanup:
  401. HRETURN( hr );
  402. } //*** CClusCfgNodeInfo::Initialize
  403. //*************************************************************************//
  404. /////////////////////////////////////////////////////////////////////////////
  405. // CClusCfgNodeInfo -- IClusCfgNodeInfo interface.
  406. /////////////////////////////////////////////////////////////////////////////
  407. //////////////////////////////////////////////////////////////////////////////
  408. //++
  409. //
  410. // CClusCfgNodeInfo::GetName
  411. //
  412. // Description:
  413. // Return the name of this computer.
  414. //
  415. // Arguments:
  416. //
  417. // Return Value:
  418. //
  419. // Remarks:
  420. // None.
  421. //
  422. //--
  423. //////////////////////////////////////////////////////////////////////////////
  424. STDMETHODIMP
  425. CClusCfgNodeInfo::GetName( BSTR * pbstrNameOut )
  426. {
  427. TraceFunc( "[IClusCfgNodeInfo]" );
  428. HRESULT hr = S_OK;
  429. if ( pbstrNameOut == NULL )
  430. {
  431. hr = THR( E_POINTER );
  432. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_NodeInfo_GetName_Pointer, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
  433. goto Cleanup;
  434. } // if:
  435. *pbstrNameOut = SysAllocString( m_bstrFullDnsName );
  436. if ( *pbstrNameOut == NULL )
  437. {
  438. hr = THR( E_OUTOFMEMORY );
  439. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetName_Memory, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr );
  440. } // if:
  441. Cleanup:
  442. HRETURN( hr );
  443. } //*** CClusCfgNodeInfo::GetName
  444. //////////////////////////////////////////////////////////////////////////////
  445. //++
  446. //
  447. // CClusCfgNodeInfo::SetName
  448. //
  449. // Description:
  450. // Change the name of this computer.
  451. //
  452. // Arguments:
  453. // IN LPCWSTR pcszNameIn
  454. // The new name for this computer.
  455. // Return Value:
  456. // S_OK
  457. // Success
  458. //
  459. // Remarks:
  460. // None.
  461. //
  462. //--
  463. //////////////////////////////////////////////////////////////////////////////
  464. STDMETHODIMP
  465. CClusCfgNodeInfo::SetName( LPCWSTR pcszNameIn )
  466. {
  467. TraceFunc1( "[IClusCfgNodeInfo] pcszNameIn = '%ls'", pcszNameIn == NULL ? L"<null>" : pcszNameIn );
  468. HRESULT hr = THR( E_NOTIMPL );
  469. HRETURN( hr );
  470. } //*** CClusCfgNodeInfo::SetName
  471. //////////////////////////////////////////////////////////////////////////////
  472. //++
  473. //
  474. // CClusCfgNodeInfo::IsMemberOfCluster
  475. //
  476. // Description:
  477. // Is this computer a member of a cluster?
  478. //
  479. // Arguments:
  480. // None.
  481. //
  482. // Return Value:
  483. // S_OK
  484. // This node is a member of a cluster.
  485. //
  486. // S_FALSE
  487. // This node is not member of a cluster.
  488. //
  489. // Other Win32 errors as HRESULT if GetNodeClusterState() fails.
  490. //
  491. // Remarks:
  492. // None.
  493. //
  494. //--
  495. //////////////////////////////////////////////////////////////////////////////
  496. STDMETHODIMP
  497. CClusCfgNodeInfo::IsMemberOfCluster( void )
  498. {
  499. TraceFunc( "[IClusCfgNodeInfo]" );
  500. HRESULT hr = S_FALSE; // default to not a cluster node.
  501. if ( m_fIsClusterNode )
  502. {
  503. hr = S_OK;
  504. } // if:
  505. HRETURN( hr );
  506. } //*** CClusCfgNodeInfo::IsMemberOfCluster
  507. //////////////////////////////////////////////////////////////////////////////
  508. //++
  509. //
  510. // CClusCfgNodeInfo::GetClusterConfigInfo
  511. //
  512. // Description:
  513. // Return the configuration information about the cluster that this
  514. // conputer belongs to.
  515. //
  516. // Arguments:
  517. // OUT IClusCfgClusterInfo ** ppClusCfgClusterInfoOut
  518. // Catches the CClusterConfigurationInfo object.
  519. //
  520. // Return Value:
  521. // S_OK
  522. // Success
  523. //
  524. // E_POINTER
  525. // The out param was NULL.
  526. //
  527. // E_OUTOFMEMORY
  528. // The CClusCfgNodeInfo object could not be allocated.
  529. //
  530. // Remarks:
  531. // None.
  532. //
  533. //--
  534. //////////////////////////////////////////////////////////////////////////////
  535. STDMETHODIMP
  536. CClusCfgNodeInfo::GetClusterConfigInfo(
  537. IClusCfgClusterInfo ** ppClusCfgClusterInfoOut
  538. )
  539. {
  540. TraceFunc( "[IClusCfgNodeInfo]" );
  541. HRESULT hr = S_OK;
  542. HRESULT hrInit = S_OK;
  543. IClusCfgSetClusterNodeInfo * pccsgni = NULL;
  544. if ( ppClusCfgClusterInfoOut == NULL )
  545. {
  546. hr = THR( E_POINTER );
  547. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetClusterConfigInfo, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
  548. goto Cleanup;
  549. } // if:
  550. if ( m_punkClusterInfo != NULL )
  551. {
  552. hr = S_OK;
  553. LogMsg( L"[SRV] CClusCfgNodeInfo::GetClusterConfigInfo() skipped object creation." );
  554. goto SkipCreate;
  555. } // if:
  556. hr = THR( CClusCfgClusterInfo::S_HrCreateInstance( &m_punkClusterInfo ) );
  557. if ( FAILED( hr ) )
  558. {
  559. goto Cleanup;
  560. } // if:
  561. m_punkClusterInfo = TraceInterface( L"CClusCfgClusterInfo", IUnknown, m_punkClusterInfo, 1 );
  562. //
  563. // KB: 01-JUN-200 GalenB
  564. //
  565. // This must be done before the CClusCfgClusterInfo class is initialized.
  566. //
  567. hr = THR( m_punkClusterInfo->TypeSafeQI( IClusCfgSetClusterNodeInfo, &pccsgni ) );
  568. if ( FAILED( hr ) )
  569. {
  570. goto Cleanup;
  571. } // if:
  572. hr = THR( pccsgni->SetClusterNodeInfo( this ) );
  573. if ( FAILED( hr ) )
  574. {
  575. goto Cleanup;
  576. } // if:
  577. //
  578. // KB: 01-JUN-200 GalenB
  579. //
  580. // This must be done after SetClusterNodeInfo() is called, but before Initialize.
  581. //
  582. hr = THR( HrSetWbemServices( m_punkClusterInfo, m_pIWbemServices ) );
  583. if ( FAILED( hr ) )
  584. {
  585. LogMsg( L"[SRV] Could not set the WBEM services on a CClusCfgClusterInfo object. (hr = %#08x)", hr );
  586. goto Cleanup;
  587. } // if:
  588. //
  589. // KB: 01-JUN-200 GalenB
  590. //
  591. // This must be done after SetClusterNodeInfo() and HrSetWbemServices are called.
  592. //
  593. hrInit = STHR( HrSetInitialize( m_punkClusterInfo, m_picccCallback, m_lcid ) );
  594. hr = hrInit; // need hrInit later...
  595. if ( FAILED( hr ) )
  596. {
  597. LogMsg( L"[SRV] Could not initialize CClusCfgClusterInfo object. (hr = %#08x)", hr );
  598. goto Cleanup;
  599. } // if:
  600. SkipCreate:
  601. if ( SUCCEEDED( hr ) )
  602. {
  603. Assert( m_punkClusterInfo != NULL );
  604. hr = THR( m_punkClusterInfo->TypeSafeQI( IClusCfgClusterInfo, ppClusCfgClusterInfoOut ) );
  605. } // if:
  606. Cleanup:
  607. //
  608. // If hrInit is not S_OK then it is most likely HR_S_RPC_S_CLUSTER_NODE_DOWN which
  609. // needs to get passed up... Everything else must have succeeded an hr must be
  610. // S_OK too.
  611. //
  612. if ( ( hr == S_OK ) && ( hrInit != S_OK ) )
  613. {
  614. hr = hrInit;
  615. } // if:
  616. LOG_STATUS_REPORT_MINOR( TASKID_Minor_Server_GetClusterInfo, L"GetClusterConfigInfo() completed.", hr );
  617. if ( pccsgni != NULL )
  618. {
  619. pccsgni->Release();
  620. } // if:
  621. HRETURN( hr );
  622. } //*** CClusCfgNodeInfo::GetClusterConfigInfo
  623. //////////////////////////////////////////////////////////////////////////////
  624. //++
  625. //
  626. // CClusCfgNodeInfo::GetOSVersion
  627. //
  628. // Description:
  629. // What is the OS version on this computer?
  630. //
  631. // Arguments:
  632. // None.
  633. //
  634. // Return Value:
  635. //
  636. // Remarks:
  637. //
  638. //--
  639. //////////////////////////////////////////////////////////////////////////////
  640. STDMETHODIMP
  641. CClusCfgNodeInfo::GetOSVersion(
  642. DWORD * pdwMajorVersionOut,
  643. DWORD * pdwMinorVersionOut,
  644. WORD * pwSuiteMaskOut,
  645. BYTE * pbProductTypeOut,
  646. BSTR * pbstrCSDVersionOut
  647. )
  648. {
  649. TraceFunc( "[IClusCfgNodeInfo]" );
  650. OSVERSIONINFOEX osv;
  651. HRESULT hr = S_OK;
  652. osv.dwOSVersionInfoSize = sizeof( osv );
  653. if ( !GetVersionEx( (OSVERSIONINFO *) &osv ) )
  654. {
  655. DWORD sc;
  656. sc = TW32( GetLastError() );
  657. hr = HRESULT_FROM_WIN32( sc );
  658. goto Cleanup;
  659. } // if: GetVersionEx() failed
  660. if ( pdwMajorVersionOut != NULL )
  661. {
  662. *pdwMajorVersionOut = osv.dwMajorVersion;
  663. } // if:
  664. if ( pdwMinorVersionOut != NULL )
  665. {
  666. *pdwMinorVersionOut = osv.dwMinorVersion;
  667. } // if:
  668. if ( pwSuiteMaskOut != NULL )
  669. {
  670. *pwSuiteMaskOut = osv.wSuiteMask;
  671. } // if:
  672. if ( pbProductTypeOut != NULL )
  673. {
  674. *pbProductTypeOut = osv.wProductType;
  675. } // if:
  676. if ( pbstrCSDVersionOut != NULL )
  677. {
  678. *pbstrCSDVersionOut = SysAllocString( osv.szCSDVersion );
  679. if ( *pbstrCSDVersionOut == NULL )
  680. {
  681. hr = THR( E_OUTOFMEMORY );
  682. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetOSVersion, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr );
  683. goto Cleanup;
  684. } // if:
  685. } // if:
  686. Cleanup:
  687. HRETURN( hr );
  688. } //*** CClusCfgNodeInfo::GetOSVersion
  689. //////////////////////////////////////////////////////////////////////////////
  690. //++
  691. //
  692. // CClusCfgNodeInfo::GetClusterVersion
  693. //
  694. // Description:
  695. // Return the cluster version information for the cluster this
  696. // computer belongs to.
  697. //
  698. // Arguments:
  699. //
  700. // Return Value:
  701. //
  702. // Remarks:
  703. // None.
  704. //
  705. //--
  706. //////////////////////////////////////////////////////////////////////////////
  707. STDMETHODIMP
  708. CClusCfgNodeInfo::GetClusterVersion(
  709. DWORD * pdwNodeHighestVersion,
  710. DWORD * pdwNodeLowestVersion
  711. )
  712. {
  713. TraceFunc( "[IClusCfgNodeInfo]" );
  714. HRESULT hr = S_OK;
  715. if ( ( pdwNodeHighestVersion == NULL ) || ( pdwNodeLowestVersion == NULL ) )
  716. {
  717. goto BadParams;
  718. } // if:
  719. *pdwNodeHighestVersion = CLUSTER_MAKE_VERSION( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION, VER_PRODUCTBUILD );
  720. *pdwNodeLowestVersion = CLUSTER_INTERNAL_PREVIOUS_HIGHEST_VERSION;
  721. goto Cleanup;
  722. BadParams:
  723. hr = THR( E_POINTER );
  724. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetClusterVersion, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
  725. Cleanup:
  726. HRETURN( hr );
  727. } //*** CClusCfgNodeInfo::GetClusterVersion
  728. //////////////////////////////////////////////////////////////////////////////
  729. //++
  730. //
  731. // CClusCfgNodeInfo::GetDriveLetterMappings
  732. //
  733. // Description:
  734. //
  735. // Arguments:
  736. // None.
  737. //
  738. // Return Value:
  739. //
  740. // Remarks:
  741. //
  742. //--
  743. //////////////////////////////////////////////////////////////////////////////
  744. STDMETHODIMP
  745. CClusCfgNodeInfo::GetDriveLetterMappings(
  746. SDriveLetterMapping * pdlmDriveLetterUsageOut
  747. )
  748. {
  749. TraceFunc( "[IClusCfgNodeInfo]" );
  750. HRESULT hr = S_FALSE;
  751. DWORD sc;
  752. DWORD cchDrives = ( 4 * 26 ) + 1; // "C:\<null>" times 26 drive letters
  753. WCHAR * pszDrives = NULL;
  754. int idx;
  755. pszDrives = new WCHAR[ cchDrives ];
  756. if ( pszDrives == NULL )
  757. {
  758. goto OutOfMemory;
  759. } // if:
  760. sc = GetLogicalDriveStrings( cchDrives, pszDrives );
  761. if ( sc == 0 )
  762. {
  763. sc = TW32( GetLastError() );
  764. hr = HRESULT_FROM_WIN32( sc );
  765. goto Cleanup;
  766. } // if:
  767. if ( sc > cchDrives )
  768. {
  769. delete [] pszDrives;
  770. pszDrives = NULL;
  771. cchDrives = sc + 1;
  772. pszDrives = new WCHAR[ cchDrives ];
  773. if ( pszDrives == NULL )
  774. {
  775. goto OutOfMemory;
  776. } // if:
  777. sc = GetLogicalDriveStrings( cchDrives, pszDrives );
  778. if ( sc == 0 )
  779. {
  780. sc = TW32( GetLastError() );
  781. hr = HRESULT_FROM_WIN32( sc );
  782. goto Cleanup;
  783. } // if:
  784. } // if:
  785. hr = THR( HrComputeDriveLetterUsage( pszDrives ) );
  786. if ( FAILED( hr ) )
  787. {
  788. goto Cleanup;
  789. } // if:
  790. hr = THR( HrComputeSystemDriveLetterUsage() );
  791. if ( FAILED( hr ) )
  792. {
  793. goto Cleanup;
  794. } // if:
  795. hr = THR( HrSetPageFileEnumIndex() );
  796. if ( FAILED( hr ) )
  797. {
  798. goto Cleanup;
  799. } // if:
  800. hr = THR( HrSetCrashDumpEnumIndex() );
  801. if ( FAILED( hr ) )
  802. {
  803. goto Cleanup;
  804. } // if:
  805. //
  806. // Load the SCSI bus and port information for each disk in each volume.
  807. //
  808. hr = THR( HrGetVolumeInfo() );
  809. if ( FAILED( hr ) )
  810. {
  811. goto Cleanup;
  812. } // if:
  813. //
  814. // Scan the drives and find those that are "system" and update any other disks on that bus
  815. // to be "??? on system bus".
  816. //
  817. hr = THR( HrUpdateSystemBusDrives() );
  818. if ( FAILED( hr ) )
  819. {
  820. goto Cleanup;
  821. } // if:
  822. //
  823. // Now that we have our array properly filled out then we need to copy that information
  824. // back to the caller.
  825. //
  826. for ( idx = 0; idx < 26; idx++ )
  827. {
  828. pdlmDriveLetterUsageOut->dluDrives[ idx ] = m_rgdluDrives[ idx ].edluUsage;
  829. } // for:
  830. goto Cleanup;
  831. OutOfMemory:
  832. hr = THR( E_OUTOFMEMORY );
  833. STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetDriveLetterMappings_Node, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr );
  834. Cleanup:
  835. delete [] pszDrives;
  836. HRETURN( hr );
  837. } //*** CClusCfgNodeInfo::GetDriveLetterMappings
  838. //////////////////////////////////////////////////////////////////////////////
  839. //++
  840. //
  841. // CClusCfgNodeInfo::GetMaxNodeCount
  842. //
  843. // Description:
  844. // Returns the maximun number of nodes for this node's product
  845. // suite type.
  846. //
  847. // Notes:
  848. //
  849. // Parameter:
  850. // pcMaxNodesOut
  851. // The maximum number of nodes allowed by this node's product
  852. // suite type.
  853. //
  854. // Return Value:
  855. // S_OK
  856. // Success.
  857. //
  858. // other HRESULT
  859. // The call failed.
  860. //
  861. //--
  862. //////////////////////////////////////////////////////////////////////////////
  863. STDMETHODIMP
  864. CClusCfgNodeInfo::GetMaxNodeCount(
  865. DWORD * pcMaxNodesOut
  866. )
  867. {
  868. TraceFunc( "[IClusCfgNodeInfo]" );
  869. HRESULT hr = S_OK;
  870. if ( pcMaxNodesOut == NULL )
  871. {
  872. hr = THR( E_POINTER );
  873. goto Cleanup;
  874. } // if:
  875. *pcMaxNodesOut = m_cMaxNodes;
  876. Cleanup:
  877. HRETURN( hr );
  878. } //*** CClusCfgNodeInfo::GetMaxNodeCount
  879. //////////////////////////////////////////////////////////////////////////////
  880. //++
  881. //
  882. // CClusCfgNodeInfo::GetProcessorInfo
  883. //
  884. // Description:
  885. // Get the processor information for this node.
  886. //
  887. // Arguments:
  888. // pwProcessorArchitectureOut
  889. // The processor architecture.
  890. //
  891. // pwProcessorLevelOut
  892. // The processor level.
  893. //
  894. // Return Value:
  895. // S_OK
  896. // Success.
  897. //
  898. // other HRESULT
  899. // The call failed.
  900. //
  901. // Remarks:
  902. // See SYSTEM_INFO in MSDN and/or the Platform SDK for more
  903. // information.
  904. //
  905. //--
  906. //////////////////////////////////////////////////////////////////////////////
  907. STDMETHODIMP
  908. CClusCfgNodeInfo::GetProcessorInfo(
  909. WORD * pwProcessorArchitectureOut
  910. , WORD * pwProcessorLevelOut
  911. )
  912. {
  913. TraceFunc( "[IClusCfgNodeInfo]" );
  914. HRESULT hr = S_OK;
  915. if ( ( pwProcessorArchitectureOut == NULL ) && ( pwProcessorLevelOut == NULL ) )
  916. {
  917. hr = THR( E_POINTER );
  918. goto Cleanup;
  919. } // if:
  920. if ( pwProcessorArchitectureOut != NULL )
  921. {
  922. *pwProcessorArchitectureOut = m_si.wProcessorArchitecture;
  923. } // if:
  924. if ( pwProcessorLevelOut != NULL )
  925. {
  926. *pwProcessorLevelOut = m_si.wProcessorLevel;
  927. } // if:
  928. Cleanup:
  929. HRETURN( hr );
  930. } //*** CClusCfgNodeInfo::GetProcessorInfo
  931. //*************************************************************************//
  932. /////////////////////////////////////////////////////////////////////////////
  933. // CClusCfgNodeInfo -- Private Methods.
  934. /////////////////////////////////////////////////////////////////////////////
  935. //////////////////////////////////////////////////////////////////////////////
  936. //++
  937. //
  938. // CClusCfgNodeInfo::HrInit
  939. //
  940. // Description:
  941. // Initialize this component.
  942. //
  943. // Arguments:
  944. // None.
  945. //
  946. // Return Value:
  947. // S_OK - Success.
  948. // Other HRESULTs.
  949. //
  950. //--
  951. //////////////////////////////////////////////////////////////////////////////
  952. HRESULT
  953. CClusCfgNodeInfo::HrInit( void )
  954. {
  955. TraceFunc( "" );
  956. HRESULT hr = S_OK;
  957. DWORD sc;
  958. DWORD dwClusterState;
  959. DWORD dwSuiteType;
  960. // IUnknown
  961. Assert( m_cRef == 1 );
  962. hr = THR( HrGetComputerName(
  963. ComputerNameDnsFullyQualified
  964. , &m_bstrFullDnsName
  965. , TRUE // fBestEffortIn
  966. ) );
  967. if ( FAILED( hr ) )
  968. {
  969. goto Cleanup;
  970. } // if:
  971. //
  972. // Get the cluster state of the node.
  973. // Ignore the case where the service does not exist so that
  974. // EvictCleanup can do its job.
  975. //
  976. sc = GetNodeClusterState( NULL, &dwClusterState );
  977. if ( ( sc != ERROR_SUCCESS ) && ( sc != ERROR_SERVICE_DOES_NOT_EXIST ) )
  978. {
  979. hr = HRESULT_FROM_WIN32( TW32( sc ) );
  980. goto Cleanup;
  981. } // if : GetClusterState() failed
  982. //
  983. // If the current cluster node state is running or not running then this node is part of a cluster.
  984. //
  985. m_fIsClusterNode = ( dwClusterState == ClusterStateNotRunning ) || ( dwClusterState == ClusterStateRunning );
  986. GetSystemInfo( &m_si );
  987. dwSuiteType = ClRtlGetSuiteType();
  988. Assert( dwSuiteType != 0 ); // we should only run on server SKUs!
  989. if ( dwSuiteType != 0 )
  990. {
  991. m_cMaxNodes = ClRtlGetDefaultNodeLimit( dwSuiteType );
  992. } // if:
  993. Cleanup:
  994. HRETURN( hr );
  995. } //*** CClusCfgNodeInfo::HrInit
  996. //////////////////////////////////////////////////////////////////////////////
  997. //++
  998. //
  999. // CClusCfgNodeInfo::HrComputeDriveLetterUsage
  1000. //
  1001. // Description:
  1002. // Fill the array with the enums that represent the drive letter usage
  1003. // and the drive letter string.
  1004. //
  1005. // Arguments:
  1006. //
  1007. //
  1008. // Return Value:
  1009. //
  1010. //
  1011. // Remarks:
  1012. // None.
  1013. //
  1014. //--
  1015. //////////////////////////////////////////////////////////////////////////////
  1016. HRESULT
  1017. CClusCfgNodeInfo::HrComputeDriveLetterUsage(
  1018. WCHAR * pszDrivesIn
  1019. )
  1020. {
  1021. TraceFunc( "" );
  1022. Assert( pszDrivesIn != NULL );
  1023. HRESULT hr = S_OK;
  1024. WCHAR * pszDrive = pszDrivesIn;
  1025. UINT uiType;
  1026. int idx;
  1027. while ( *pszDrive != NULL )
  1028. {
  1029. uiType = GetDriveType( pszDrive );
  1030. CharUpper( pszDrive );
  1031. idx = pszDrive[ 0 ] - 'A';
  1032. hr = THR( StringCchCopyW( m_rgdluDrives[ idx ].szDrive, ARRAYSIZE( m_rgdluDrives[ idx ].szDrive ), pszDrive ) );
  1033. if ( FAILED( hr ) )
  1034. {
  1035. goto Cleanup;
  1036. } // if:
  1037. m_rgdluDrives[ idx ].edluUsage = (EDriveLetterUsage) uiType;
  1038. pszDrive += 4;
  1039. } // while:
  1040. Cleanup:
  1041. HRETURN( hr );
  1042. } //*** CClusCfgNodeInfo::HrComputeDriveLetterUsage
  1043. //////////////////////////////////////////////////////////////////////////////
  1044. //++
  1045. //
  1046. // CClusCfgNodeInfo::HrComputeSystemDriveLetterUsage
  1047. //
  1048. // Description:
  1049. // Fill the array with the enums that represent the drive letter usage.
  1050. //
  1051. // Arguments:
  1052. //
  1053. //
  1054. // Return Value:
  1055. //
  1056. //
  1057. // Remarks:
  1058. // None.
  1059. //
  1060. //--
  1061. //////////////////////////////////////////////////////////////////////////////
  1062. HRESULT
  1063. CClusCfgNodeInfo::HrComputeSystemDriveLetterUsage( void )
  1064. {
  1065. TraceFunc( "" );
  1066. HRESULT hr = S_OK;
  1067. BSTR bstrBootLogicalDisk = NULL;
  1068. BSTR bstrSystemDevice = NULL;
  1069. BSTR bstrSystemLogicalDisk = NULL;
  1070. int idx;
  1071. // hr = THR( HrLoadOperatingSystemInfo( m_picccCallback, m_pIWbemServices, &bstrBootDevice, &bstrSystemDevice ) );
  1072. // if ( FAILED( hr ) )
  1073. // {
  1074. // goto Cleanup;
  1075. // } // if:
  1076. hr = THR( HrGetSystemDevice( &bstrSystemDevice ) );
  1077. if ( FAILED( hr ) )
  1078. {
  1079. goto Cleanup;
  1080. } // if:
  1081. hr = HrConvertDeviceVolumeToLogicalDisk( bstrSystemDevice, &bstrSystemLogicalDisk );
  1082. if ( HRESULT_CODE( hr ) == ERROR_INVALID_FUNCTION )
  1083. {
  1084. //
  1085. // system volume is an EFI volume on IA64 and won't have a logical disk anyway...
  1086. //
  1087. hr = S_OK;
  1088. } // if:
  1089. else if ( hr == S_OK )
  1090. {
  1091. idx = bstrSystemLogicalDisk[ 0 ] - 'A';
  1092. m_rgdluDrives[ idx ].edluUsage = dluSYSTEM;
  1093. } // else if:
  1094. if ( FAILED( hr ) )
  1095. {
  1096. THR( hr );
  1097. goto Cleanup;
  1098. } // if:
  1099. hr = THR( HrGetBootLogicalDisk( &bstrBootLogicalDisk ) );
  1100. if ( FAILED( hr ) )
  1101. {
  1102. goto Cleanup;
  1103. } // if:
  1104. idx = bstrBootLogicalDisk[ 0 ] - 'A';
  1105. m_rgdluDrives[ idx ].edluUsage = dluSYSTEM;
  1106. Cleanup:
  1107. TraceSysFreeString( bstrBootLogicalDisk );
  1108. TraceSysFreeString( bstrSystemDevice );
  1109. TraceSysFreeString( bstrSystemLogicalDisk );
  1110. HRETURN( hr );
  1111. } //*** CClusCfgNodeInfo::HrComputeSystemDriveLetterUsage
  1112. /////////////////////////////////////////////////////////////////////////////
  1113. //++
  1114. //
  1115. // CClusCfgNodeInfo::HrSetPageFileEnumIndex
  1116. //
  1117. // Description:
  1118. // Mark the drives that have paging files on them.
  1119. //
  1120. // Arguments:
  1121. //
  1122. //
  1123. // Return Value:
  1124. // S_OK
  1125. // Success.
  1126. //
  1127. // Remarks:
  1128. // None.
  1129. //
  1130. //--
  1131. //////////////////////////////////////////////////////////////////////////////
  1132. HRESULT
  1133. CClusCfgNodeInfo::HrSetPageFileEnumIndex( void )
  1134. {
  1135. TraceFunc( "" );
  1136. HRESULT hr = S_OK;
  1137. WCHAR szLogicalDisks[ 26 ];
  1138. int cLogicalDisks = 0;
  1139. int idx;
  1140. int idxDrive;
  1141. hr = THR( HrGetPageFileLogicalDisks( m_picccCallback, m_pIWbemServices, szLogicalDisks, &cLogicalDisks ) );
  1142. if ( FAILED( hr ) )
  1143. {
  1144. goto Cleanup;
  1145. } // if:
  1146. for ( idx = 0; idx < cLogicalDisks; idx++ )
  1147. {
  1148. idxDrive = szLogicalDisks[ idx ] - L'A';
  1149. m_rgdluDrives[ idxDrive ].edluUsage = dluSYSTEM;
  1150. } // for:
  1151. Cleanup:
  1152. HRETURN( hr );
  1153. } //*** CClusCfgNodeInfo::HrSetPageFileEnumIndex
  1154. /////////////////////////////////////////////////////////////////////////////
  1155. //++
  1156. //
  1157. // CClusCfgNodeInfo::HrSetCrashDumpEnumIndex
  1158. //
  1159. // Description:
  1160. // Mark the drive that has a crash dump file on it.
  1161. //
  1162. // Arguments:
  1163. //
  1164. //
  1165. // Return Value:
  1166. // S_OK
  1167. // Success.
  1168. //
  1169. // Remarks:
  1170. // None.
  1171. //
  1172. //--
  1173. //////////////////////////////////////////////////////////////////////////////
  1174. HRESULT
  1175. CClusCfgNodeInfo::HrSetCrashDumpEnumIndex( void )
  1176. {
  1177. TraceFunc( "" );
  1178. HRESULT hr = S_OK;
  1179. BSTR bstrCrashDumpDrive = NULL;
  1180. int idx;
  1181. hr = THR( HrGetCrashDumpLogicalDisk( &bstrCrashDumpDrive ) );
  1182. if ( FAILED( hr ) )
  1183. {
  1184. goto Cleanup;
  1185. } // if:
  1186. idx = bstrCrashDumpDrive[ 0 ] - L'A';
  1187. m_rgdluDrives[ idx ].edluUsage = dluSYSTEM;
  1188. Cleanup:
  1189. TraceSysFreeString( bstrCrashDumpDrive );
  1190. HRETURN( hr );
  1191. } //*** CClusCfgNodeInfo::HrSetCrashDumpEnumIndex
  1192. /////////////////////////////////////////////////////////////////////////////
  1193. //++
  1194. //
  1195. // CClusCfgNodeInfo::HrGetVolumeInfo
  1196. //
  1197. // Description:
  1198. // Gather the volume info for the drive letters that we have already
  1199. // have loaded. We need the drive letter info to promote those drives
  1200. // from their basic type to a system type if there are on the same SCSI
  1201. // bus and port as one of the five kinds of system disks.
  1202. //
  1203. // Arguments:
  1204. // None.
  1205. //
  1206. // Return Value:
  1207. // S_OK
  1208. // Success.
  1209. //
  1210. // Remarks:
  1211. // If any if the IOCTL wrapper functions fail then that drive letter will
  1212. // simply not be able to be promoted to a system disk. This is not a big
  1213. // deal and it's okay to skip gathering the data for those disks.
  1214. //
  1215. //--
  1216. //////////////////////////////////////////////////////////////////////////////
  1217. HRESULT
  1218. CClusCfgNodeInfo::HrGetVolumeInfo( void )
  1219. {
  1220. TraceFunc( "" );
  1221. HRESULT hr = S_OK;
  1222. int idxDriveLetter;
  1223. WCHAR szDevice[ 7 ];
  1224. DWORD sc;
  1225. HANDLE hVolume = INVALID_HANDLE_VALUE;
  1226. VOLUME_DISK_EXTENTS * pvde = NULL;
  1227. DWORD cbvde = 0;
  1228. SCSI_ADDRESS saAddress;
  1229. SSCSIInfo * psi = NULL;
  1230. //
  1231. // Initialize the disk extents buffer. This will be re-allocated and re-used.
  1232. //
  1233. cbvde = sizeof( VOLUME_DISK_EXTENTS );
  1234. pvde = (PVOLUME_DISK_EXTENTS) TraceAlloc( 0, cbvde );
  1235. if ( pvde == NULL )
  1236. {
  1237. hr = THR( E_OUTOFMEMORY );
  1238. goto Cleanup;
  1239. } // if:
  1240. //
  1241. // Loop through each drive letter.
  1242. //
  1243. for ( idxDriveLetter = 0; idxDriveLetter < 26; idxDriveLetter++ )
  1244. {
  1245. //
  1246. // Cleanup.
  1247. //
  1248. if ( hVolume != INVALID_HANDLE_VALUE )
  1249. {
  1250. CloseHandle( hVolume );
  1251. hVolume = INVALID_HANDLE_VALUE;
  1252. } // if:
  1253. //
  1254. // Only need to check where we actually have a drive letter that could be on a system bus.
  1255. //
  1256. if ( ( m_rgdluDrives[ idxDriveLetter ].edluUsage == dluUNKNOWN )
  1257. || ( m_rgdluDrives[ idxDriveLetter ].edluUsage == dluNETWORK_DRIVE )
  1258. || ( m_rgdluDrives[ idxDriveLetter ].edluUsage == dluRAM_DISK ) )
  1259. {
  1260. continue;
  1261. } // if:
  1262. hr = THR( StringCchPrintfW( szDevice, ARRAYSIZE( szDevice ), L"\\\\.\\%c:", m_rgdluDrives[ idxDriveLetter ].szDrive[ 0 ] ) );
  1263. if ( FAILED( hr ) )
  1264. {
  1265. goto Cleanup;
  1266. } // if:
  1267. //
  1268. // Get handle to the disk
  1269. //
  1270. hVolume = CreateFileW( szDevice, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1271. if ( hVolume == INVALID_HANDLE_VALUE )
  1272. {
  1273. //
  1274. // Log the problem and continue. Make the HRESULT a warning
  1275. // HRESULT since we don't want an [ERR] showing up in the log
  1276. // file.
  1277. //
  1278. sc = TW32( GetLastError() );
  1279. hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc );
  1280. 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 );
  1281. continue;
  1282. } // if:
  1283. sc = TW32E( ScGetDiskExtents( hVolume, &pvde, &cbvde ), ERROR_INVALID_FUNCTION );
  1284. switch ( sc )
  1285. {
  1286. //
  1287. // 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...
  1288. //
  1289. case ERROR_INVALID_FUNCTION:
  1290. {
  1291. //
  1292. // If we got the address info then we need to save if off with the drive letter usage struct.
  1293. //
  1294. sc = ScGetSCSIAddressInfo( hVolume, &saAddress );
  1295. if ( sc == ERROR_SUCCESS )
  1296. {
  1297. psi = (SSCSIInfo *) TraceAlloc( 0, sizeof( SSCSIInfo ) * 1 );
  1298. if ( psi == NULL )
  1299. {
  1300. hr = THR( E_OUTOFMEMORY );
  1301. goto Cleanup;
  1302. } // if:
  1303. psi->uiSCSIPort = saAddress.PortNumber;
  1304. psi->uiSCSIBus = saAddress.PathId;
  1305. m_rgdluDrives[ idxDriveLetter ].cDisks = 1;
  1306. m_rgdluDrives[ idxDriveLetter ].psiInfo = psi;
  1307. psi =NULL;
  1308. } // if:
  1309. else
  1310. {
  1311. //
  1312. // Log the problem and continue. Make the HRESULT a
  1313. // warning HRESULT since we don't want an [ERR]
  1314. // showing up in the log file.
  1315. //
  1316. hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc );
  1317. 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 );
  1318. } // else:
  1319. break;
  1320. } // case: ERROR_INVALID_FUNCTION
  1321. //
  1322. // The volume at the drive letter may be an multi disk volume so we have to process all of the disks...
  1323. //
  1324. case ERROR_SUCCESS:
  1325. {
  1326. DWORD idxExtent;
  1327. HANDLE hDisk = INVALID_HANDLE_VALUE;
  1328. STORAGE_DEVICE_NUMBER sdn;
  1329. BOOL fOpenNewDevice = TRUE;
  1330. BOOL fRetainSCSIInfo = TRUE;
  1331. WCHAR sz[ _MAX_PATH ];
  1332. //
  1333. // Allocate enough structs to hold the scsi address info for this volume.
  1334. //
  1335. psi = (SSCSIInfo *) TraceAlloc( 0, sizeof( SSCSIInfo ) * pvde->NumberOfDiskExtents );
  1336. if ( psi == NULL )
  1337. {
  1338. hr = THR( E_OUTOFMEMORY );
  1339. goto Cleanup;
  1340. } // if:
  1341. //
  1342. // Get the device number for the device that we have open. If it is not the same as the current device from the
  1343. // drive extents that we are working on then we need to open another device. When working with a basic disk the
  1344. // volume that we already have open is the one disk and we can just use it. If we are using a multi disk volume
  1345. // then we have to open each disk in turn.
  1346. //
  1347. sc = ScGetStorageDeviceNumber( hVolume, &sdn );
  1348. if ( sc == ERROR_SUCCESS )
  1349. {
  1350. if ( ( pvde->NumberOfDiskExtents == 1 ) && ( pvde->Extents[ 0 ].DiskNumber == sdn.DeviceNumber ) )
  1351. {
  1352. fOpenNewDevice = FALSE;
  1353. } // if:
  1354. } // if:
  1355. for ( idxExtent = 0; idxExtent < pvde->NumberOfDiskExtents; idxExtent++ )
  1356. {
  1357. if ( fOpenNewDevice )
  1358. {
  1359. hr = THR( StringCchPrintfW( sz, ARRAYSIZE( sz ), g_szPhysicalDriveFormat, pvde->Extents[ idxExtent ].DiskNumber ) );
  1360. if ( FAILED( hr ) )
  1361. {
  1362. goto Cleanup;
  1363. } // if:
  1364. hDisk = CreateFileW( sz, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  1365. if ( hDisk == INVALID_HANDLE_VALUE )
  1366. {
  1367. //
  1368. // Log the problem and continue. Make the HRESULT
  1369. // a warning HRESULT since we don't want an [ERR]
  1370. // showing up in the log file.
  1371. //
  1372. sc = TW32( GetLastError() );
  1373. hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc );
  1374. LOG_STATUS_REPORT_STRING( L"Could not create a handle to drive \"%1!ws!\". Ignoring and skipping device.", sz, hr );
  1375. continue;
  1376. } // if:
  1377. } // if:
  1378. sc = TW32( ScGetSCSIAddressInfo( fOpenNewDevice ? hDisk : hVolume, &saAddress ) );
  1379. if ( sc == ERROR_SUCCESS )
  1380. {
  1381. psi[ idxExtent ].uiSCSIPort = saAddress.PortNumber;
  1382. psi[ idxExtent ].uiSCSIBus = saAddress.PathId;
  1383. if ( hDisk != INVALID_HANDLE_VALUE )
  1384. {
  1385. VERIFY( CloseHandle( hDisk ) );
  1386. hDisk = INVALID_HANDLE_VALUE;
  1387. } // if:
  1388. } // if:
  1389. else
  1390. {
  1391. //
  1392. // Having a multi-device volume that doesn't support
  1393. // getting SCSI information seems like an unlikely
  1394. // situation.
  1395. //
  1396. Assert( pvde->NumberOfDiskExtents == 1 );
  1397. //
  1398. // Log the problem and continue. Make the HRESULT a warning
  1399. // HRESULT since we don't want an [ERR] showing up in the log
  1400. // file.
  1401. //
  1402. // An example of a volume that might cause this is a
  1403. // USB memory stick.
  1404. //
  1405. hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc );
  1406. 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 );
  1407. //
  1408. // Tell the block of code below to free the already
  1409. // allocated SCSI info. Let's also leave now...
  1410. //
  1411. fRetainSCSIInfo = FALSE;
  1412. break;
  1413. } // else:
  1414. } // for: each extent
  1415. //
  1416. // Should we keep the SCSI information from above?
  1417. //
  1418. if ( fRetainSCSIInfo )
  1419. {
  1420. m_rgdluDrives[ idxDriveLetter ].cDisks = pvde->NumberOfDiskExtents;
  1421. m_rgdluDrives[ idxDriveLetter ].psiInfo = psi;
  1422. psi = NULL;
  1423. } // if: save the SCSI info...
  1424. else
  1425. {
  1426. //
  1427. // Zero out this data for safety. This information is
  1428. // processed later and I want to ensure that code does
  1429. // not try to process the SCSI info that we could not
  1430. // get for this/these extents.
  1431. //
  1432. m_rgdluDrives[ idxDriveLetter ].cDisks = 0;
  1433. m_rgdluDrives[ idxDriveLetter ].psiInfo = NULL;
  1434. TraceFree( psi );
  1435. psi = NULL;
  1436. } // else: do not save the SCSI info...
  1437. break;
  1438. } // case: ERROR_SUCCESS
  1439. default:
  1440. //
  1441. // Log the problem and continue. Make the HRESULT a warning
  1442. // HRESULT since we don't want an [ERR] showing up in the log
  1443. // file.
  1444. //
  1445. hr = MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, sc );
  1446. LOG_STATUS_REPORT_STRING( L"Could not get the drive extents of drive \"%1!ws!\". Ignoring and skipping device.", m_rgdluDrives[ idxDriveLetter ].szDrive, hr );
  1447. break;
  1448. } // switch: sc from ScGetDiskExtents()
  1449. } // for: each drive letter
  1450. //
  1451. // If we didn't go to cleanup then whatever status may be in hr is no longer interesting and we
  1452. // should return S_OK to the caller.
  1453. //
  1454. hr = S_OK;
  1455. Cleanup:
  1456. TraceFree( psi );
  1457. TraceFree( pvde );
  1458. if ( hVolume != INVALID_HANDLE_VALUE )
  1459. {
  1460. VERIFY( CloseHandle( hVolume ) );
  1461. } // if:
  1462. HRETURN( hr );
  1463. } //*** CClusCfgNodeInfo::HrGetVolumeInfo
  1464. /////////////////////////////////////////////////////////////////////////////
  1465. //++
  1466. //
  1467. // CClusCfgNodeInfo::ScGetDiskExtents
  1468. //
  1469. // Description:
  1470. // Get the volume extents info.
  1471. //
  1472. // Arguments:
  1473. // hVolumeIn
  1474. // The volume to get the extents for.
  1475. //
  1476. // ppvdeInout
  1477. // Buffer that holds the disk extents.
  1478. //
  1479. // pcbvdeInout
  1480. // Size of the buffer that holds the disk extents.
  1481. //
  1482. // Return Value:
  1483. // ERROR_SUCCESS
  1484. // Success.
  1485. //
  1486. // Remarks:
  1487. // None.
  1488. //
  1489. //--
  1490. //////////////////////////////////////////////////////////////////////////////
  1491. DWORD
  1492. CClusCfgNodeInfo::ScGetDiskExtents(
  1493. HANDLE hVolumeIn
  1494. , VOLUME_DISK_EXTENTS ** ppvdeInout
  1495. , DWORD * pcbvdeInout
  1496. )
  1497. {
  1498. TraceFunc( "" );
  1499. Assert( hVolumeIn != INVALID_HANDLE_VALUE );
  1500. Assert( ppvdeInout != NULL );
  1501. Assert( pcbvdeInout != NULL );
  1502. DWORD sc = ERROR_SUCCESS;
  1503. DWORD cbSize;
  1504. int cTemp;
  1505. BOOL fRet;
  1506. PVOLUME_DISK_EXTENTS pvdeTemp = NULL;
  1507. //
  1508. // Since this buffer is re-used it should be cleaned up.
  1509. //
  1510. ZeroMemory( *ppvdeInout, *pcbvdeInout );
  1511. for ( cTemp = 0; cTemp < 2; cTemp++ )
  1512. {
  1513. fRet = DeviceIoControl(
  1514. hVolumeIn
  1515. , IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
  1516. , NULL
  1517. , 0
  1518. , *ppvdeInout
  1519. , *pcbvdeInout
  1520. , &cbSize
  1521. , FALSE
  1522. );
  1523. if ( fRet == FALSE )
  1524. {
  1525. sc = GetLastError();
  1526. if ( sc == ERROR_MORE_DATA )
  1527. {
  1528. *pcbvdeInout = sizeof( VOLUME_DISK_EXTENTS ) + ( sizeof( DISK_EXTENT ) * (*ppvdeInout)->NumberOfDiskExtents );
  1529. pvdeTemp = (PVOLUME_DISK_EXTENTS) TraceReAlloc( *ppvdeInout, *pcbvdeInout, HEAP_ZERO_MEMORY );
  1530. if ( pvdeTemp == NULL )
  1531. {
  1532. sc = TW32( ERROR_OUTOFMEMORY );
  1533. break;
  1534. } // if:
  1535. *ppvdeInout = pvdeTemp;
  1536. continue;
  1537. } // if:
  1538. else
  1539. {
  1540. break;
  1541. } // else:
  1542. } // if:
  1543. else
  1544. {
  1545. sc = ERROR_SUCCESS;
  1546. break;
  1547. } // else:
  1548. } // for:
  1549. //
  1550. // Shouldn't go through the loop more than twice!
  1551. //
  1552. Assert( cTemp != 2 );
  1553. HRETURN( sc );
  1554. } //*** CClusCfgNodeInfo::ScGetDiskExtents
  1555. /////////////////////////////////////////////////////////////////////////////
  1556. //++
  1557. //
  1558. // CClusCfgNodeInfo::ScGetSCSIAddressInfo
  1559. //
  1560. // Description:
  1561. // Get the SCSI info for the passed in drive.
  1562. //
  1563. // Arguments:
  1564. // hDiskIn
  1565. // The "disk" to send the IOCTL to.
  1566. //
  1567. // psaAddressOut
  1568. // The SCSI address info.
  1569. //
  1570. // Return Value:
  1571. // S_OK
  1572. // Success.
  1573. //
  1574. // Remarks:
  1575. // None.
  1576. //
  1577. //--
  1578. //////////////////////////////////////////////////////////////////////////////
  1579. DWORD
  1580. CClusCfgNodeInfo::ScGetSCSIAddressInfo(
  1581. HANDLE hDiskIn
  1582. , SCSI_ADDRESS * psaAddressOut
  1583. )
  1584. {
  1585. TraceFunc( "" );
  1586. Assert( hDiskIn != INVALID_HANDLE_VALUE );
  1587. Assert( psaAddressOut != NULL );
  1588. DWORD sc = ERROR_SUCCESS;
  1589. BOOL fRet;
  1590. DWORD cb;
  1591. ZeroMemory( psaAddressOut, sizeof( *psaAddressOut ) );
  1592. fRet = DeviceIoControl(
  1593. hDiskIn
  1594. , IOCTL_SCSI_GET_ADDRESS
  1595. , NULL
  1596. , 0
  1597. , psaAddressOut
  1598. , sizeof( *psaAddressOut )
  1599. , &cb
  1600. , FALSE
  1601. );
  1602. if ( fRet == FALSE )
  1603. {
  1604. //
  1605. // Not all devices support this IOCTL and they will be skipped by the caller.
  1606. // There is no need to make this noisy since a failure is expected.
  1607. //
  1608. sc = GetLastError();
  1609. goto Cleanup;
  1610. } // if:
  1611. Cleanup:
  1612. HRETURN( sc );
  1613. } //*** CClusCfgNodeInfo::ScGetSCSIAddressInfo
  1614. /////////////////////////////////////////////////////////////////////////////
  1615. //++
  1616. //
  1617. // CClusCfgNodeInfo::ScGetStorageDeviceNumber
  1618. //
  1619. // Description:
  1620. // Get the device number info for the passed in volume.
  1621. //
  1622. // Arguments:
  1623. // hDiskIn
  1624. // The "disk" to send the IOCTL to.
  1625. //
  1626. // psdnOut
  1627. // The storage device number.
  1628. //
  1629. // Return Value:
  1630. // S_OK
  1631. // Success.
  1632. //
  1633. // Remarks:
  1634. // None.
  1635. //
  1636. //--
  1637. //////////////////////////////////////////////////////////////////////////////
  1638. DWORD
  1639. CClusCfgNodeInfo::ScGetStorageDeviceNumber(
  1640. HANDLE hDiskIn
  1641. , STORAGE_DEVICE_NUMBER * psdnOut
  1642. )
  1643. {
  1644. TraceFunc( "" );
  1645. Assert( hDiskIn != INVALID_HANDLE_VALUE );
  1646. Assert( psdnOut != NULL );
  1647. DWORD sc = ERROR_SUCCESS;
  1648. BOOL fRet;
  1649. DWORD cb;
  1650. ZeroMemory( psdnOut, sizeof( *psdnOut ) );
  1651. fRet = DeviceIoControl(
  1652. hDiskIn
  1653. , IOCTL_STORAGE_GET_DEVICE_NUMBER
  1654. , NULL
  1655. , 0
  1656. , psdnOut
  1657. , sizeof( *psdnOut )
  1658. , &cb
  1659. , FALSE
  1660. );
  1661. if ( fRet == FALSE )
  1662. {
  1663. sc = GetLastError();
  1664. goto Cleanup;
  1665. } // if:
  1666. Cleanup:
  1667. HRETURN( sc );
  1668. } //*** CClusCfgNodeInfo::ScGetStorageDeviceNumber
  1669. /////////////////////////////////////////////////////////////////////////////
  1670. //++
  1671. //
  1672. // CClusCfgNodeInfo::HrUpdateSystemBusDrives
  1673. //
  1674. // Description:
  1675. // Find all the "SYSTEM" drives and mark any other disks on those drives
  1676. // as "??? on system bus".
  1677. //
  1678. // Arguments:
  1679. // None.
  1680. //
  1681. // Return Value:
  1682. // S_OK
  1683. // Success.
  1684. //
  1685. // Remarks:
  1686. // None.
  1687. //
  1688. //--
  1689. //////////////////////////////////////////////////////////////////////////////
  1690. HRESULT
  1691. CClusCfgNodeInfo::HrUpdateSystemBusDrives( void )
  1692. {
  1693. TraceFunc( "" );
  1694. HRESULT hr = S_OK;
  1695. int idxOuter; // the index of the drives in m_rgdluDrives
  1696. int idxInner; // the index of the drives that we are scanning
  1697. DWORD idxOuterExtents;
  1698. DWORD idxInnerExtents;
  1699. UINT uiSCSIPort;
  1700. UINT uiSCSIBus;
  1701. //
  1702. // Loop through each drive letter looking for those that are "system".
  1703. //
  1704. for ( idxOuter = 0; idxOuter < 26; idxOuter++ )
  1705. {
  1706. //
  1707. // We only need to worry about system disks.
  1708. //
  1709. if ( m_rgdluDrives[ idxOuter ].edluUsage != dluSYSTEM )
  1710. {
  1711. continue;
  1712. } // if:
  1713. //
  1714. // Loop through the the "extents" records which contain the bus and port info for each disk in that volume.
  1715. //
  1716. for ( idxOuterExtents = 0; idxOuterExtents < m_rgdluDrives[ idxOuter ].cDisks; idxOuterExtents++ )
  1717. {
  1718. uiSCSIPort = m_rgdluDrives[ idxOuter ].psiInfo[ idxOuterExtents ].uiSCSIPort;
  1719. uiSCSIBus = m_rgdluDrives[ idxOuter ].psiInfo[ idxOuterExtents ].uiSCSIBus;
  1720. //
  1721. // Loop through the drives again to find those that are on the same bus and port as the
  1722. // disk at idxOuter.
  1723. //
  1724. for ( idxInner = 0; idxInner < 26; idxInner++ )
  1725. {
  1726. //
  1727. // Skip the index that we are checking. May need to skip any other disks that are
  1728. // still marked dluSYSTEM?
  1729. //
  1730. // Skip any indexes that don't have a drive...
  1731. //
  1732. if ( ( idxInner == idxOuter ) || ( m_rgdluDrives[ idxInner ].edluUsage == dluUNKNOWN ) )
  1733. {
  1734. continue;
  1735. } // if:
  1736. //
  1737. // Loop through the port and bus info for the drives on the volume at idxInner.
  1738. //
  1739. for ( idxInnerExtents = 0; idxInnerExtents < m_rgdluDrives[ idxInner ].cDisks; idxInnerExtents++ )
  1740. {
  1741. if ( ( uiSCSIPort == m_rgdluDrives[ idxInner ].psiInfo[ idxInnerExtents ].uiSCSIPort )
  1742. && ( uiSCSIBus == m_rgdluDrives[ idxInner ].psiInfo[ idxInnerExtents ].uiSCSIBus ) )
  1743. {
  1744. //
  1745. // Promote the usage enum to reflect that it is on the system bus.
  1746. //
  1747. // BTW: += does not work for enums!
  1748. //
  1749. m_rgdluDrives[ idxInner ].edluUsage = (EDriveLetterUsage)( m_rgdluDrives[ idxInner ].edluUsage + dluSTART_OF_SYSTEM_BUS );
  1750. //
  1751. // If any drive in the volume is on a system bus and port then we are done.
  1752. //
  1753. break;
  1754. } // if:
  1755. } // for: each inner extent
  1756. } // for: each inner drive letter
  1757. } // for: each outer extent
  1758. } // for: each outer drive letter
  1759. HRETURN( hr );
  1760. } //*** CClusCfgNodeInfo::HrUpdateSystemBusDrives