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.

999 lines
25 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. clusinfo.c
  6. Abstract:
  7. Retrieves cluster information: net name and TCP/IP address.
  8. Public functions from this module:
  9. bGetClusterNameInfo
  10. This code is a total hack. It relies on internal knowledge about
  11. the registry structure of clustering and NetworkName and TCP/IP adddress:
  12. Questionable Assumptions:
  13. Directly under the resource GUID there will be a value called
  14. "Type" that holds the fixed resource name string.
  15. The resource type names "Network Name" and "IP Address" will
  16. never change or be localized. (They shouldn't be localized, since
  17. they are keys, but I don't see a description value in the registry.)
  18. There will be a key called "Parameters" that will never change
  19. (or get localized).
  20. Bad Assumptions:
  21. IP Address resource stores a value "Address" that holds
  22. a REG_SZ string of the tcpip address.
  23. Network Name resource stores a value "Name" that holds a REG_SZ
  24. string of the network name.
  25. General strategy:
  26. 1. Open self resource based on resource string from SplSvcOpen.
  27. 2. Enumerate dependencies looking for net name.
  28. 3. Find net name and save group name.
  29. 4. Enumerate dependencies of net name looking for IP addresses.
  30. 5. Save all found IP addresses.
  31. Author:
  32. Albert Ting (AlbertT) 25-Sept-96
  33. Revision History:
  34. --*/
  35. #include "precomp.hxx"
  36. #pragma hdrstop
  37. #include "clusinfo.hxx"
  38. #define GROUP_NAME_LEN_HINT MAX_PATH
  39. #define RESOURCE_NAME_LEN_HINT MAX_PATH
  40. #define TYPE_NAME_LEN_HINT MAX_PATH
  41. LPCTSTR gszType = TEXT( "Type" );
  42. LPCTSTR gszParameters = TEXT( "Parameters" );
  43. DWORD kGuidStringByteSize = 100;
  44. /********************************************************************
  45. Callback for Querying cluster registry.
  46. ********************************************************************/
  47. typedef struct _REG_QUERY_VALUE {
  48. HKEY hKey;
  49. LPCTSTR pszValue;
  50. } REG_QUERY_VALUE, *PREG_QUERY_VALUE;
  51. BOOL
  52. bAllocClusterRegQueryValue(
  53. HANDLE hUserData,
  54. PALLOC_DATA pAllocData
  55. )
  56. {
  57. DWORD dwStatus;
  58. PREG_QUERY_VALUE pRegQueryValue = (PREG_QUERY_VALUE)hUserData;
  59. dwStatus = ClusterRegQueryValue( pRegQueryValue->hKey,
  60. pRegQueryValue->pszValue,
  61. NULL,
  62. pAllocData->pBuffer,
  63. &pAllocData->cbBuffer );
  64. if( dwStatus != NO_ERROR ){
  65. SetLastError( dwStatus );
  66. return FALSE;
  67. }
  68. return TRUE;
  69. }
  70. /********************************************************************
  71. Callback for retrieving group name: GetClusterResourceState.
  72. ********************************************************************/
  73. BOOL
  74. bAllocGetClusterResourceState(
  75. HANDLE hUserData,
  76. PALLOC_DATA pAllocData
  77. )
  78. {
  79. DWORD cchGroupName = pAllocData->cbBuffer / sizeof( TCHAR );
  80. CLUSTER_RESOURCE_STATE crs;
  81. crs = GetClusterResourceState( (HRESOURCE)hUserData,
  82. NULL,
  83. 0,
  84. (LPTSTR)pAllocData->pBuffer,
  85. &cchGroupName );
  86. pAllocData->cbBuffer = cchGroupName * sizeof( TCHAR );
  87. return crs != ClusterResourceStateUnknown;
  88. }
  89. /********************************************************************
  90. Callback for enumerating group resources.
  91. ********************************************************************/
  92. typedef struct _RESOURCE_ENUM {
  93. HRESENUM hResEnum;
  94. DWORD dwIndex;
  95. } RESOURCE_ENUM, *PRESOURCE_ENUM;
  96. BOOL
  97. bAllocClusterResourceEnum(
  98. HANDLE hUserData,
  99. PALLOC_DATA pAllocData
  100. )
  101. {
  102. PRESOURCE_ENUM pResourceEnum = (PRESOURCE_ENUM)hUserData;
  103. DWORD dwStatus;
  104. DWORD cchName = pAllocData->cbBuffer / sizeof( TCHAR );
  105. DWORD dwType;
  106. dwStatus = ClusterResourceEnum( pResourceEnum->hResEnum,
  107. pResourceEnum->dwIndex,
  108. &dwType,
  109. (LPTSTR)pAllocData->pBuffer,
  110. &cchName );
  111. pAllocData->cbBuffer = cchName * sizeof( TCHAR );
  112. if( dwStatus != NO_ERROR ){
  113. SetLastError( dwStatus );
  114. return FALSE;
  115. }
  116. return TRUE;
  117. }
  118. /********************************************************************
  119. End callbacks.
  120. ********************************************************************/
  121. typedef struct _CLUSINFO_DATA {
  122. LPCTSTR pszResource;
  123. LPCTSTR pszValue;
  124. } CLUSINFO_DATA, *PCLUSINFO_DATA;
  125. CLUSINFO_DATA gaClusInfoDataMain[] = {
  126. { TEXT( "Network Name" ), TEXT( "Name" ) },
  127. { NULL, NULL }
  128. };
  129. CLUSINFO_DATA gaClusInfoDataNetName[] = {
  130. { TEXT( "IP Address" ), TEXT( "Address" ) },
  131. { NULL, NULL }
  132. };
  133. enum {
  134. ClusInfoName = 0,
  135. ClusInfoAddress,
  136. ClusInfoMax
  137. };
  138. typedef struct _CLUSINFO_DATAOUT {
  139. UINT cbData;
  140. LPCTSTR pszData;
  141. } CLUSINFO_DATAOUT, *PCLUSINFO_DATAOUT;
  142. BOOL
  143. bProcessResourceRegKey(
  144. IN HKEY hKey,
  145. IN PCLUSINFO_DATA pClusInfoData,
  146. IN OUT PCLUSINFO_DATAOUT pClusInfoDataOut
  147. )
  148. /*++
  149. Routine Description:
  150. Checks whether a resource in a cluster matches any of the ClusInfoData
  151. resources. If it does, fill one parameter into the ClusInfoDataOut
  152. parameter (comma delimited string).
  153. Arguments:
  154. hKey - Key to read.
  155. pClusInfoData - Array of different ClusInfoData types that we
  156. want to look for.
  157. pClusInfoDataOut - Container that receives data we have found.
  158. This should be valid on input, since we append to form
  159. a comma delimited string.
  160. Return Value:
  161. TRUE - Success: this may or may not have filled in one of the OUT
  162. parameters, but we didn't encounter any errors trying to read
  163. the resource.
  164. FALSE - Failure (LastError set).
  165. --*/
  166. {
  167. HKEY hKeyParameters = NULL;
  168. LPCTSTR pszType = NULL;
  169. BOOL bStatus = TRUE;
  170. REG_QUERY_VALUE rqv;
  171. DWORD dwStatus;
  172. UINT i;
  173. LPCTSTR pszNewSingleData = NULL;
  174. LPTSTR pszNewData = NULL;
  175. UINT cbNewSingleData;
  176. UINT cbNewData;
  177. rqv.hKey = hKey;
  178. rqv.pszValue = gszType;
  179. pszType = (LPCTSTR)pAllocRead( &rqv,
  180. bAllocClusterRegQueryValue,
  181. TYPE_NAME_LEN_HINT,
  182. NULL );
  183. if( !pszType ){
  184. DBGMSG( DBG_WARN,
  185. ( "bProcessResourceRegKey: ClusterRegOpenKey failed %d\n",
  186. GetLastError() ));
  187. bStatus = FALSE;
  188. goto Done;
  189. }
  190. //
  191. // Walk through the list and check if there is a match.
  192. //
  193. for( i=0; bStatus && pClusInfoData[i].pszResource; ++i ){
  194. UINT cchLen;
  195. if( lstrcmp( pszType, pClusInfoData[i].pszResource )){
  196. //
  197. // No match, continue.
  198. //
  199. continue;
  200. }
  201. //
  202. // Found a match, read a value out of the
  203. // "parameters" key.
  204. //
  205. dwStatus = ClusterRegOpenKey( hKey,
  206. gszParameters,
  207. KEY_READ,
  208. &hKeyParameters );
  209. if( dwStatus != NO_ERROR ){
  210. DBGMSG( DBG_WARN,
  211. ( "bProcessResourceRegKey: ClusterRegOpenKey failed %d\n",
  212. dwStatus ));
  213. bStatus = FALSE;
  214. goto LoopDone;
  215. }
  216. rqv.hKey = hKeyParameters;
  217. rqv.pszValue = pClusInfoData[i].pszValue;
  218. pszNewSingleData = (LPCTSTR)pAllocRead( &rqv,
  219. bAllocClusterRegQueryValue,
  220. TYPE_NAME_LEN_HINT,
  221. NULL );
  222. if( !pszNewSingleData ){
  223. DBGMSG( DBG_WARN,
  224. ( "bProcessResource: Read "TSTR" failed %d\n",
  225. pClusInfoData[i].pszResource, GetLastError() ));
  226. bStatus = FALSE;
  227. goto LoopDone;
  228. }
  229. DBGMSG( DBG_TRACE,
  230. ( "bProcessResource: Read successful: "TSTR"\n",
  231. pszNewSingleData, GetLastError() ));
  232. cchLen = lstrlen( pszNewSingleData );
  233. //
  234. // We have new data in pszNewData, add it to the end.
  235. //
  236. cbNewSingleData = ( cchLen + 1 ) * sizeof( TCHAR );
  237. cbNewData = cbNewSingleData + pClusInfoDataOut[i].cbData;
  238. pszNewData = (LPTSTR)LocalAlloc( LMEM_FIXED, cbNewData );
  239. if( !pszNewData ){
  240. bStatus = FALSE;
  241. goto Done;
  242. }
  243. //
  244. // If we have something, copy it over then add a ',' character.
  245. //
  246. if( pClusInfoDataOut[i].cbData ){
  247. //
  248. // Copy it over.
  249. //
  250. CopyMemory( (PVOID)pszNewData,
  251. (PVOID)pClusInfoDataOut[i].pszData,
  252. pClusInfoDataOut[i].cbData );
  253. //
  254. // Convert the NULL to a comma in our new data.
  255. //
  256. pszNewData[pClusInfoDataOut[i].cbData /
  257. sizeof( pClusInfoDataOut[i].pszData[0] ) - 1] = TEXT( ',' );
  258. }
  259. //
  260. // Copy the new string.
  261. //
  262. CopyMemory( (PBYTE)pszNewData + pClusInfoDataOut[i].cbData,
  263. (PVOID)pszNewSingleData,
  264. cbNewSingleData );
  265. DBGMSG( DBG_TRACE,
  266. ( "bProcessResourceRegKey: Updated ("TSTR") + ("TSTR") = ("TSTR")\n",
  267. DBGSTR(pClusInfoDataOut[i].pszData), pszNewSingleData, pszNewData ));
  268. //
  269. // Now swap the newly created memory with the old one.
  270. // We'll free pszNewSingleData and store the old memory there.
  271. //
  272. pClusInfoDataOut[i].cbData = cbNewData;
  273. LocalFree( (HLOCAL)pszNewSingleData );
  274. pszNewSingleData = pClusInfoDataOut[i].pszData;
  275. pClusInfoDataOut[i].pszData = pszNewData;
  276. pszNewData = NULL;
  277. LoopDone:
  278. if( pszNewSingleData ){
  279. LocalFree( (HLOCAL)pszNewSingleData );
  280. }
  281. if( pszNewData ){
  282. LocalFree( (HLOCAL)pszNewData );
  283. }
  284. if( hKeyParameters && ClusterRegCloseKey( hKeyParameters )){
  285. DBGMSG( DBG_WARN,
  286. ( "bProcessResource: ClusterRegCloseKey1 failed %x\n",
  287. hKey ));
  288. }
  289. }
  290. Done:
  291. if( pszType ){
  292. LocalFree( (HLOCAL)pszType );
  293. }
  294. return bStatus;
  295. }
  296. BOOL
  297. bProcessResource(
  298. IN HCLUSTER hCluster,
  299. IN HRESOURCE hResource,
  300. IN PCLUSINFO_DATA pClusInfoData,
  301. OUT PCLUSINFO_DATAOUT pClusInfoDataOut
  302. )
  303. /*++
  304. Routine Description:
  305. Checks whether a resource in a cluster matches any of the ClusInfoData
  306. resources. If it does, fill one parameter into the ClusInfoDataOut
  307. parameter.
  308. Arguments:
  309. Return Value:
  310. TRUE - Success: this may or may not have filled in one of the OUT
  311. parameters, but we didn't encounter any errors trying to read
  312. the resource.
  313. FALSE - Failure (LastError set).
  314. --*/
  315. {
  316. HKEY hKey = NULL;
  317. LPCTSTR pszType = NULL;
  318. BOOL bStatus = FALSE;
  319. UNREFERENCED_PARAMETER( hCluster );
  320. hKey = GetClusterResourceKey( hResource, KEY_READ );
  321. if( !hKey ){
  322. DBGMSG( DBG_WARN,
  323. ( "bProcessResource: GetClusterResourceKey failed %d\n",
  324. GetLastError() ));
  325. goto Done;
  326. }
  327. bStatus = bProcessResourceRegKey( hKey,
  328. pClusInfoData,
  329. pClusInfoDataOut );
  330. Done:
  331. if( hKey && ClusterRegCloseKey( hKey )){
  332. DBGMSG( DBG_WARN,
  333. ( "bProcessResource: ClusterRegCloseKey2 failed %x\n",
  334. hKey ));
  335. }
  336. return bStatus;
  337. }
  338. /********************************************************************
  339. Enum dependency support. This is handled by calling a callback
  340. with the retieved handle.
  341. ********************************************************************/
  342. typedef BOOL (*ENUM_CALLBACK )(
  343. HCLUSTER hCluster,
  344. HRESOURCE hResource,
  345. HANDLE hData
  346. );
  347. BOOL
  348. bHandleEnumDependencies(
  349. IN HCLUSTER hCluster,
  350. IN HRESOURCE hResource,
  351. IN ENUM_CALLBACK pfnEnumCallback,
  352. IN HANDLE hData,
  353. OUT PUINT puSuccess OPTIONAL
  354. );
  355. /********************************************************************
  356. Callbacks for EnumDependencies.
  357. ********************************************************************/
  358. BOOL
  359. bEnumDependencyCallbackMain(
  360. IN HCLUSTER hCluster,
  361. IN HRESOURCE hResource,
  362. IN HANDLE hData
  363. );
  364. BOOL
  365. bEnumDependencyCallbackNetName(
  366. IN HCLUSTER hCluster,
  367. IN HRESOURCE hResource,
  368. IN HANDLE hData
  369. );
  370. /********************************************************************
  371. Functions.
  372. ********************************************************************/
  373. BOOL
  374. bHandleEnumDependencies(
  375. IN HCLUSTER hCluster,
  376. IN HRESOURCE hResource,
  377. IN ENUM_CALLBACK pfnEnumCallback,
  378. IN HANDLE hData,
  379. OUT PUINT puSuccess OPTIONAL
  380. )
  381. /*++
  382. Routine Description:
  383. Takes a resource and calls pfnEnumCallback for each of the dependent
  384. resources.
  385. Arguments:
  386. hResource - Resource that holds dependencies to check.
  387. pfnEnumCallback - Callback routine.
  388. hData - Private data.
  389. puSuccess - Number of successful hits.
  390. Return Value:
  391. TRUE - success, FALSE - failure.
  392. --*/
  393. {
  394. RESOURCE_ENUM ResourceEnum;
  395. LPCTSTR pszResource;
  396. HRESOURCE hResourceDependency;
  397. UINT uSuccess = 0;
  398. BOOL bStatus = TRUE;
  399. ResourceEnum.hResEnum = ClusterResourceOpenEnum(
  400. hResource,
  401. CLUSTER_RESOURCE_ENUM_DEPENDS );
  402. if( !ResourceEnum.hResEnum ){
  403. DBGMSG( DBG_WARN,
  404. ( "bHandleEnumDependencies: ClusterResourceOpenEnum failed %d\n",
  405. GetLastError() ));
  406. bStatus = FALSE;
  407. } else {
  408. //
  409. // Walk through all the dependent resources and call
  410. // the callback function to process them.
  411. //
  412. for( ResourceEnum.dwIndex = 0; ; ++ResourceEnum.dwIndex ){
  413. pszResource = (LPCTSTR)pAllocRead(
  414. (HANDLE)&ResourceEnum,
  415. bAllocClusterResourceEnum,
  416. RESOURCE_NAME_LEN_HINT,
  417. NULL );
  418. if( !pszResource ){
  419. SPLASSERT( GetLastError() == ERROR_NO_MORE_ITEMS );
  420. bStatus = FALSE;
  421. break;
  422. }
  423. hResourceDependency = OpenClusterResource( hCluster, pszResource );
  424. if( !hResourceDependency ){
  425. DBGMSG( DBG_WARN,
  426. ( "bHandleEnumDependencies: OpenClusterResource failed "TSTR" %d\n",
  427. pszResource, GetLastError() ));
  428. bStatus = FALSE;
  429. } else {
  430. if( pfnEnumCallback( hCluster, hResourceDependency, hData )){
  431. ++uSuccess;
  432. }
  433. if( !CloseClusterResource( hResourceDependency )){
  434. DBGMSG( DBG_WARN,
  435. ( "bProcessResource: CloseClusterResource failed "TSTR" %x %d\n",
  436. pszResource, hResourceDependency, GetLastError() ));
  437. }
  438. }
  439. LocalFree( (HLOCAL)pszResource );
  440. }
  441. if( ClusterResourceCloseEnum( ResourceEnum.hResEnum )){
  442. DBGMSG( DBG_WARN,
  443. ( "bProcessResource: ClusterResourceCloseEnum failed %x\n",
  444. ResourceEnum.hResEnum ));
  445. }
  446. }
  447. if( puSuccess ){
  448. *puSuccess = uSuccess;
  449. }
  450. return bStatus;
  451. }
  452. BOOL
  453. bEnumDependencyCallbackMain(
  454. IN HCLUSTER hCluster,
  455. IN HRESOURCE hResource,
  456. IN HANDLE hData
  457. )
  458. /*++
  459. Routine Description:
  460. This routine processes the dependent resources of the main resource.
  461. It is called once for each.
  462. When we encounter net name, we'll do the same procedure except
  463. look for tcpip addresses.
  464. Arguments:
  465. hResource - This resource is an enumerated dependency.
  466. hData - User supplied ata.
  467. Return Value:
  468. TRUE - Found
  469. FALSE - Not found.
  470. --*/
  471. {
  472. BOOL bStatus;
  473. BOOL bReturn = FALSE;
  474. UINT uSuccess;
  475. bStatus = bProcessResource( hCluster,
  476. hResource,
  477. gaClusInfoDataMain,
  478. (PCLUSINFO_DATAOUT)hData );
  479. //
  480. // If it's successful, it must have been "NetName," since that's
  481. // the only thing we're looking for. In that case, build
  482. // names off of its tcpip addresses.
  483. //
  484. if( bStatus ){
  485. PCLUSINFO_DATAOUT pClusInfoDataOut = (PCLUSINFO_DATAOUT)hData;
  486. bReturn = TRUE;
  487. //
  488. // Use the proper index for tcpip addresses.
  489. //
  490. bStatus = bHandleEnumDependencies(
  491. hCluster,
  492. hResource,
  493. bEnumDependencyCallbackNetName,
  494. (HANDLE)&pClusInfoDataOut[ClusInfoAddress],
  495. &uSuccess );
  496. if( !bStatus || !uSuccess ){
  497. DBGMSG( DBG_WARN,
  498. ( "bEnumDependencyCallbackMain: failed to get ip addr %d %d %d\n",
  499. bStatus, uSuccess, GetLastError() ));
  500. }
  501. } else {
  502. DBGMSG( DBG_WARN,
  503. ( "bEnumDependencyCallbackMain: failed to find net name %d\n",
  504. GetLastError() ));
  505. }
  506. return bReturn;
  507. }
  508. BOOL
  509. bEnumDependencyCallbackNetName(
  510. IN HCLUSTER hCluster,
  511. IN HRESOURCE hResource,
  512. IN HANDLE hData
  513. )
  514. /*++
  515. Routine Description:
  516. This routine processes the dependent resources of the net name
  517. resource.
  518. Arguments:
  519. hResource - This resource is an enumerated dependency.
  520. hData - User supplied ata.
  521. Return Value:
  522. TRUE - continue,
  523. FALSE - stop.
  524. --*/
  525. {
  526. BOOL bStatus;
  527. bStatus = bProcessResource( hCluster,
  528. hResource,
  529. gaClusInfoDataNetName,
  530. (PCLUSINFO_DATAOUT)hData );
  531. return bStatus;
  532. }
  533. /********************************************************************
  534. Main entry point.
  535. ********************************************************************/
  536. BOOL
  537. bGetClusterNameInfo(
  538. IN LPCTSTR pszResource,
  539. OUT LPCTSTR* ppszName,
  540. OUT LPCTSTR* ppszAddress
  541. )
  542. /*++
  543. Routine Description:
  544. Retrieves information about a given resource.
  545. Arguments:
  546. pszResource - Name of the resource. Must not be NULL.
  547. ppszName - Receives LocalAlloc'd string of cluster name.
  548. ppszAddress - Receives LocalAlloc'd TCPIP address name string.
  549. Return Value:
  550. TRUE - Success, *ppszName, *ppszAddress both valid and
  551. must be LocalFree'd when no longer needed.
  552. FALSE - Failed, *ppszName, *ppszAddress both NULL.
  553. LastError set.
  554. --*/
  555. {
  556. HCLUSTER hCluster = NULL;
  557. HRESOURCE hResource = NULL;
  558. HRESENUM hResEnum = NULL;
  559. LPCTSTR pszGroupName = NULL;
  560. UINT uSuccess = 0;
  561. UINT i;
  562. CLUSINFO_DATAOUT aClusInfoDataOut[ClusInfoMax];
  563. //
  564. // Free the strings if there were allocated earlier so we can
  565. // start clean.
  566. //
  567. if( *ppszName ){
  568. LocalFree( (HLOCAL)*ppszName );
  569. *ppszName = NULL;
  570. }
  571. if( *ppszAddress ){
  572. LocalFree( (HLOCAL)*ppszAddress );
  573. *ppszAddress = NULL;
  574. }
  575. ZeroMemory( aClusInfoDataOut, sizeof( aClusInfoDataOut ));
  576. //
  577. // Open the cluster and acquire the information.
  578. //
  579. hCluster = OpenCluster( NULL );
  580. if( !hCluster ){
  581. DBGMSG( DBG_WARN,
  582. ( "bGetClusterNameInfo: OpenCluster failed %d\n",
  583. GetLastError() ));
  584. goto Done;
  585. }
  586. hResource = OpenClusterResource(
  587. hCluster,
  588. pszResource );
  589. if( !hResource ){
  590. DBGMSG( DBG_WARN,
  591. ( "bGetClusterNameInfo: OpenClusterResource "TSTR" failed %d\n",
  592. pszResource, GetLastError() ));
  593. goto Done;
  594. }
  595. //
  596. // Enum through the dependent resources in the group looking for either
  597. // type "IP Address" or "Network Name." These shouldn't be
  598. // localized since they are registry keys (not values).
  599. //
  600. bHandleEnumDependencies( hCluster,
  601. hResource,
  602. bEnumDependencyCallbackMain,
  603. (HANDLE)&aClusInfoDataOut[ClusInfoName],
  604. &uSuccess );
  605. Done:
  606. if( hResource && !CloseClusterResource( hResource )){
  607. DBGMSG( DBG_WARN,
  608. ( "bGetCluseterNameInfo: CloseClusterResource failed %d\n",
  609. GetLastError() ));
  610. }
  611. if( hCluster && !CloseCluster( hCluster )){
  612. DBGMSG( DBG_WARN,
  613. ( "bGetClusterNameInfo: CloseCluster failed %d\n",
  614. GetLastError() ));
  615. }
  616. if( !uSuccess ){
  617. DBGMSG( DBG_WARN,
  618. ( "bGetCluseterNameInfo: No NetName enumerated back! %d\n",
  619. GetLastError() ));
  620. for( i=0; i<COUNTOF( aClusInfoDataOut ); ++i ){
  621. if( aClusInfoDataOut[i].pszData ){
  622. LocalFree( (HLOCAL)aClusInfoDataOut[i].pszData );
  623. }
  624. }
  625. } else {
  626. *ppszName = aClusInfoDataOut[ClusInfoName].pszData;
  627. *ppszAddress = aClusInfoDataOut[ClusInfoAddress].pszData;
  628. }
  629. DBGMSG( DBG_TRACE,
  630. ( "bGetClusterNameInfo: uSuccess %d "TSTR" "TSTR"\n",
  631. uSuccess, DBGSTR( *ppszName ), DBGSTR( *ppszAddress )));
  632. return uSuccess != 0;
  633. }
  634. /*++
  635. Routine Description:
  636. Gets the GUID for a resource.
  637. Arguments:
  638. hResource - handle obtained via OpenClusterResource
  639. Return Value:
  640. ERROR_SUCCESS - The function completed successfully.
  641. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  642. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  643. Win32 error code - The function failed.
  644. --*/
  645. DWORD
  646. GetIDFromName(
  647. IN HRESOURCE hResource,
  648. OUT LPWSTR *ppszID
  649. )
  650. {
  651. DWORD dwError = ERROR_INVALID_PARAMETER;
  652. if (hResource && ppszID)
  653. {
  654. //
  655. // Set the out parameter to something known
  656. //
  657. *ppszID = NULL;
  658. //
  659. // Should be able to hold the string representation of a guid
  660. //
  661. DWORD cbBuf = kGuidStringByteSize;
  662. if (*ppszID = (LPWSTR)LocalAlloc(LMEM_FIXED, cbBuf))
  663. {
  664. if ((dwError = ClusterResourceControl(hResource,
  665. NULL,
  666. CLUSCTL_RESOURCE_GET_ID,
  667. NULL,
  668. 0,
  669. *ppszID,
  670. cbBuf,
  671. &cbBuf)) == ERROR_MORE_DATA)
  672. {
  673. LocalFree(*ppszID);
  674. if (*ppszID = (LPWSTR)LocalAlloc(LMEM_FIXED, cbBuf))
  675. {
  676. dwError = ClusterResourceControl(hResource,
  677. NULL,
  678. CLUSCTL_RESOURCE_GET_ID,
  679. NULL,
  680. 0,
  681. *ppszID,
  682. cbBuf,
  683. &cbBuf);
  684. }
  685. else
  686. {
  687. dwError = GetLastError();
  688. }
  689. }
  690. //
  691. // Free the memory if getting the ID failed
  692. //
  693. if (dwError != ERROR_SUCCESS && *ppszID)
  694. {
  695. LocalFree(*ppszID);
  696. *ppszID = NULL;
  697. }
  698. }
  699. else
  700. {
  701. dwError = GetLastError();
  702. }
  703. }
  704. DBGMSG(DBG_TRACE, ("GetIDFromName returns %u\n", dwError));
  705. return dwError;
  706. }