Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1839 lines
46 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. resrcapi.c
  5. Abstract:
  6. Public interfaces for managing cluster resources.
  7. Author:
  8. John Vert (jvert) 15-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "clusapip.h"
  12. //
  13. // Local function prototypes
  14. //
  15. HRESOURCE
  16. InitClusterResource(
  17. IN HRES_RPC hResource,
  18. IN LPCWSTR lpszResourceName,
  19. IN PCLUSTER pCluster
  20. );
  21. HRESTYPEENUM
  22. ClusterResourceTypeOpenEnumFromCandidate(
  23. IN HCLUSTER hCluster,
  24. IN LPCWSTR lpszResourceTypeName,
  25. IN DWORD dwType
  26. );
  27. BOOL
  28. FindNetworkWorker(
  29. IN HRES_RPC hResource,
  30. IN PCLUSTER Cluster,
  31. OUT LPWSTR lpBuffer,
  32. IN OUT LPDWORD nSize
  33. );
  34. /****
  35. @func DWORD | ClusterResourceTypeOpenEnumFromCandidate | Tries to
  36. enumerate the nodes that support a resource type
  37. using a candidate node in the cluster
  38. @parm IN HCLUSTER | hCluster | Handle to the cluster
  39. @parm IN LPCWSTR | lpszResourceTypeName | Pointer to the name of the
  40. resource type
  41. @parm IN DWORD | dwType | A bitmask of the type of properties
  42. to be enumerated. Currently, the only defined type is
  43. CLUSTER_RESOURCE_TYPE_ENUM_NODES.
  44. @rdesc Returns NULL if the operation is unsuccessful. For
  45. detailed information about the error, call the Win32
  46. function GetLastError (). A handle to the enumeration
  47. on success.
  48. @xref <f ClusterResourceTypeOpenEnum>
  49. ****/
  50. HRESTYPEENUM
  51. ClusterResourceTypeOpenEnumFromCandidate(
  52. IN HCLUSTER hCluster,
  53. IN LPCWSTR lpszResourceTypeName,
  54. IN DWORD dwType
  55. )
  56. {
  57. DWORD dwError = ERROR_SUCCESS;
  58. DWORD dwEnumType;
  59. HCLUSENUM hNodeEnum = 0;
  60. WCHAR NameBuf[50];
  61. DWORD NameLen, i, j;
  62. HCLUSTER hClusNode;
  63. PCLUSTER pClus;
  64. BOOL bFoundSp5OrHigherNode = FALSE;
  65. PENUM_LIST Enum = NULL;
  66. BOOL bNodeDown = FALSE;
  67. //
  68. // Open node enumeration in the cluster
  69. //
  70. hNodeEnum = ClusterOpenEnum(hCluster, CLUSTER_ENUM_NODE);
  71. if (hNodeEnum == NULL) {
  72. dwError = GetLastError();
  73. TIME_PRINT(("ClusterResourceTypeOpenEnum - ClusterOpenEnum failed %d\n",
  74. dwError));
  75. goto error_exit;
  76. }
  77. //
  78. // Enumerate the nodes in the cluster. If you find a live node
  79. // that is NT4Sp5 or higher, try to enumerate the resource types
  80. // from that node
  81. //
  82. for (i=0; ; i++) {
  83. dwError = ERROR_SUCCESS;
  84. NameLen = sizeof(NameBuf)/sizeof(WCHAR);
  85. dwError = ClusterEnum(hNodeEnum, i, &dwEnumType, NameBuf, &NameLen);
  86. if (dwError == ERROR_NO_MORE_ITEMS) {
  87. dwError = ERROR_SUCCESS;
  88. break;
  89. } else if (dwError != ERROR_SUCCESS) {
  90. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - ClusterEnum %d returned error %d\n",
  91. i,dwError));
  92. goto error_exit;
  93. }
  94. if (dwEnumType != CLUSTER_ENUM_NODE) {
  95. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Invalid Type %d returned from ClusterEnum\n",
  96. dwEnumType));
  97. goto error_exit;
  98. }
  99. hClusNode = OpenCluster(NameBuf);
  100. if (hClusNode == NULL) {
  101. bNodeDown = TRUE;
  102. dwError = GetLastError();
  103. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - OpenCluster %ws failed %d\n",
  104. NameBuf, dwError));
  105. continue;
  106. }
  107. pClus = GET_CLUSTER(hClusNode);
  108. dwError = ApiCreateResTypeEnum(pClus->RpcBinding,
  109. lpszResourceTypeName,
  110. dwType,
  111. &Enum);
  112. if (!CloseCluster(hClusNode)) {
  113. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - CloseCluster %ws failed %d\n",
  114. NameBuf, GetLastError()));
  115. }
  116. if (dwError == RPC_S_PROCNUM_OUT_OF_RANGE) {
  117. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Node %ws is also NT4Sp3/Sp4, skipping...\n",
  118. NameBuf));
  119. dwError = ERROR_SUCCESS;
  120. continue;
  121. } else if ((dwError == ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND) ||
  122. (dwError == ERROR_INVALID_PARAMETER) ||
  123. (dwError == ERROR_NOT_ENOUGH_MEMORY)) {
  124. //
  125. // The above three error codes returned by the RPC
  126. // are fatal and so it is not wise to continue any further.
  127. //
  128. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - ApiCreateResTypeEnum fatally failed %d at node %ws\n",
  129. dwError,NameBuf));
  130. goto error_exit;
  131. }
  132. else if (dwError != ERROR_SUCCESS) {
  133. bNodeDown = TRUE;
  134. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - ApiCreateResTypeEnum failed %d (Node %ws down possibly)\n",
  135. dwError,NameBuf));
  136. continue;
  137. }
  138. else {
  139. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Found node %ws NT4Sp5 or higher\n",
  140. NameBuf));
  141. bFoundSp5OrHigherNode = TRUE;
  142. break;
  143. }
  144. }
  145. if (!bFoundSp5OrHigherNode) {
  146. //
  147. // Did not find a node higher than NT4Sp4.
  148. //
  149. if (!bNodeDown) {
  150. //
  151. // Assume all nodes are NT4Sp3/Sp4. Send the open node enumeration
  152. // back to the client since we assume NT4Sp3/Sp4 supports
  153. // all resource types. The client is responsible for closing
  154. // the open node enumeration. Note that before a handle to
  155. // the enumeration is returned back, we need to fake the type
  156. // of enumeration.
  157. //
  158. // Chittur Subbaraman (chitturs) - 09/08/98
  159. //
  160. // How do we know that the resource type parameter
  161. // in this case is a valid one ?
  162. //
  163. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Assuming all nodes are NT4Sp3 ...\n"));
  164. Enum = (PENUM_LIST)hNodeEnum;
  165. for (j=0; j<i; j++) {
  166. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Faking type ...\n"));
  167. Enum->Entry[j].Type = CLUSTER_RESOURCE_TYPE_ENUM_NODES;
  168. }
  169. } else {
  170. //
  171. // Atleast 1 node was unreachable. Can't enumerate properly.
  172. //
  173. dwError = ERROR_NODE_NOT_AVAILABLE;
  174. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - At least 1 node in this mixed mode/Sp3/Sp4 cluster is down ...\n"));
  175. TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Can't enumerate properly !!!\n"));
  176. goto error_exit;
  177. }
  178. } else {
  179. ClusterCloseEnum(hNodeEnum);
  180. }
  181. return((HRESTYPEENUM)Enum);
  182. error_exit:
  183. if (hNodeEnum != NULL) {
  184. ClusterCloseEnum(hNodeEnum);
  185. }
  186. SetLastError(dwError);
  187. return(NULL);
  188. }
  189. HRESOURCE
  190. InitClusterResource(
  191. IN HRES_RPC hResource,
  192. IN LPCWSTR lpszResourceName,
  193. IN PCLUSTER pCluster
  194. )
  195. /*++
  196. Routine Description:
  197. Allocates and initializes a CRESOURCE. The initialized CRESOURCE
  198. is linked onto the cluster structure.
  199. Arguments:
  200. hResource - Supplies the RPC resource handle.
  201. lpszResourceName - Supplies the name of the resource.
  202. pCluster - Supplies the cluster
  203. Return Value:
  204. A pointer to the initialized CRESOURCE structure.
  205. NULL on error.
  206. --*/
  207. {
  208. PCRESOURCE Resource;
  209. Resource = LocalAlloc(LMEM_FIXED, sizeof(CRESOURCE));
  210. if (Resource == NULL) {
  211. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  212. return(NULL);
  213. }
  214. Resource->Name = LocalAlloc(LMEM_FIXED, (lstrlenW(lpszResourceName)+1)*sizeof(WCHAR));
  215. if (Resource->Name == NULL) {
  216. LocalFree(Resource);
  217. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  218. return(NULL);
  219. }
  220. lstrcpyW(Resource->Name, lpszResourceName);
  221. Resource->Cluster = pCluster;
  222. Resource->hResource = hResource;
  223. InitializeListHead(&Resource->NotifyList);
  224. //
  225. // Link new resource onto the cluster structure.
  226. //
  227. EnterCriticalSection(&pCluster->Lock);
  228. InsertHeadList(&pCluster->ResourceList, &Resource->ListEntry);
  229. LeaveCriticalSection(&pCluster->Lock);
  230. return ((HRESOURCE)Resource);
  231. }
  232. HRESOURCE
  233. WINAPI
  234. CreateClusterResource(
  235. IN HGROUP hGroup,
  236. IN LPCWSTR lpszResourceName,
  237. IN LPCWSTR lpszResourceType,
  238. IN DWORD dwFlags
  239. )
  240. /*++
  241. Routine Description:
  242. Creates a new resource in the cluster.
  243. Arguments:
  244. hGroup - Supplies a handle to the group that the resource should be
  245. created in.
  246. lpszResourceName - Supplies the new resource's name. The specified name
  247. must be unique within the cluster.
  248. lpszResourceType - Supplies the new resources type. The specified
  249. resource type must be installed in the cluster.
  250. dwFlags - Supplies optional flags. Currently defined flags are:
  251. CLUSTER_RESOURCE_SEPARATE_MONITOR - This resource should be created
  252. in a separate resource monitor instead of the shared resource monitor.
  253. Return Value:
  254. non-NULL - returns an open handle to the specified cluster.
  255. NULL - The operation failed. Extended error status is available
  256. using GetLastError()
  257. --*/
  258. {
  259. HRESOURCE Resource;
  260. HRES_RPC hRes;
  261. PCGROUP Group;
  262. error_status_t Status = ERROR_SUCCESS;
  263. Group = (PCGROUP)hGroup;
  264. WRAP_NULL(hRes,
  265. (ApiCreateResource(Group->hGroup,
  266. lpszResourceName,
  267. lpszResourceType,
  268. dwFlags,
  269. &Status)),
  270. &Status,
  271. Group->Cluster);
  272. if (hRes == NULL) {
  273. SetLastError(Status);
  274. return(NULL);
  275. }
  276. //
  277. // Initialize the newly created resource and return
  278. // the HRESOURCE.
  279. //
  280. Resource = InitClusterResource(hRes, lpszResourceName, Group->Cluster);
  281. if (Resource == NULL) {
  282. Status = GetLastError();
  283. ApiCloseResource(&hRes);
  284. SetLastError(Status);
  285. }
  286. return(Resource);
  287. }
  288. HRESOURCE
  289. WINAPI
  290. OpenClusterResource(
  291. IN HCLUSTER hCluster,
  292. IN LPCWSTR lpszResourceName
  293. )
  294. /*++
  295. Routine Description:
  296. Opens a handle to the specified resource
  297. Arguments:
  298. hCluster - Supplies a handle to the cluster
  299. lpszResourceName - Supplies the name of the resource to be opened
  300. Return Value:
  301. non-NULL - returns an open handle to the specified cluster.
  302. NULL - The operation failed. Extended error status is available
  303. using GetLastError()
  304. --*/
  305. {
  306. HRESOURCE Resource;
  307. HRES_RPC hRes;
  308. error_status_t Status = ERROR_SUCCESS;
  309. PCLUSTER Cluster = (PCLUSTER)hCluster;
  310. WRAP_NULL(hRes,
  311. (ApiOpenResource(Cluster->RpcBinding,
  312. lpszResourceName,
  313. &Status)),
  314. &Status,
  315. Cluster);
  316. if ((hRes == NULL) || (Status != ERROR_SUCCESS)) {
  317. SetLastError(Status);
  318. return(NULL);
  319. }
  320. //
  321. // Initialize the newly created resource and return
  322. // the HRESOURCE.
  323. //
  324. Resource = InitClusterResource(hRes, lpszResourceName, Cluster);
  325. if (Resource == NULL) {
  326. Status = GetLastError();
  327. ApiCloseResource(&hRes);
  328. SetLastError(Status);
  329. }
  330. return(Resource);
  331. }
  332. BOOL
  333. WINAPI
  334. CloseClusterResource(
  335. IN HRESOURCE hResource
  336. )
  337. /*++
  338. Routine Description:
  339. Closes a resource handle returned from OpenClusterResource
  340. Arguments:
  341. hResource - Supplies the resource handle
  342. Return Value:
  343. TRUE - The operation was successful.
  344. FALSE - The operation failed. Extended error status is available
  345. using GetLastError()
  346. --*/
  347. {
  348. PCRESOURCE Resource;
  349. PCLUSTER Cluster;
  350. Resource = (PCRESOURCE)hResource;
  351. Cluster = (PCLUSTER)Resource->Cluster;
  352. //
  353. // Unlink resource from cluster list.
  354. //
  355. EnterCriticalSection(&Cluster->Lock);
  356. RemoveEntryList(&Resource->ListEntry);
  357. //
  358. // Remove any notifications posted against this resource.
  359. //
  360. RundownNotifyEvents(&Resource->NotifyList, Resource->Name);
  361. //if the cluster is dead and the reconnect has failed,
  362. //the Resource->hResource might be NULL if s_apiopenresource for
  363. //this group failed on a reconnect
  364. //the cluster may be dead and hresource may be non null, say
  365. //if reconnectgroups succeeded but the reconnect resources
  366. //failed
  367. //At reconnect, the old context is saved in the obsolete
  368. //list for deletion when the cluster handle is closed or
  369. //when the next api call is made
  370. if ((Cluster->Flags & CLUS_DEAD) && (Resource->hResource))
  371. {
  372. RpcSmDestroyClientContext(&Resource->hResource);
  373. LeaveCriticalSection(&Cluster->Lock);
  374. goto FnExit;
  375. }
  376. LeaveCriticalSection(&Cluster->Lock);
  377. // Close RPC context handle
  378. //
  379. ApiCloseResource(&Resource->hResource);
  380. FnExit:
  381. //
  382. // Free memory allocations
  383. //
  384. LocalFree(Resource->Name);
  385. LocalFree(Resource);
  386. //
  387. // Give the cluster a chance to clean up in case this
  388. // resource was the only thing keeping it around.
  389. //
  390. CleanupCluster(Cluster);
  391. return(TRUE);
  392. }
  393. DWORD
  394. WINAPI
  395. DeleteClusterResource(
  396. IN HRESOURCE hResource
  397. )
  398. /*++
  399. Routine Description:
  400. Permanently deletes a resource from the cluster.
  401. The specified resource must be offline.
  402. Arguments:
  403. hResource - Supplies the resource to be deleted
  404. Return Value:
  405. ERROR_SUCCESS if successful
  406. If the function fails, the return value is an error value.
  407. If the resource is not currently offline, the error value
  408. is ERROR_RESOURCE_NOT_OFFLINE.
  409. --*/
  410. {
  411. PCRESOURCE Resource;
  412. DWORD Status;
  413. Resource = (PCRESOURCE)hResource;
  414. WRAP(Status,
  415. (ApiDeleteResource(Resource->hResource)),
  416. Resource->Cluster);
  417. return(Status);
  418. }
  419. CLUSTER_RESOURCE_STATE
  420. WINAPI
  421. GetClusterResourceState(
  422. IN HRESOURCE hResource,
  423. OUT OPTIONAL LPWSTR lpszNodeName,
  424. IN OUT LPDWORD lpcchNodeName,
  425. OUT OPTIONAL LPWSTR lpszGroupName,
  426. IN OUT LPDWORD lpcchGroupName
  427. )
  428. /*++
  429. Routine Description:
  430. Returns the resource's current state and the node where
  431. it is currently online.
  432. Arguments:
  433. hResource - Supplies a handle to a cluster resource
  434. lpszNodeName - Returns the name of the node in the cluster where the
  435. given resource is currently online
  436. lpcchNodeName - Points to a variable that specifies the size, in characters,
  437. of the buffer pointed to by the lpszNodeName parameter. This size
  438. should include the terminating null character. When the function returns,
  439. the variable pointed to by lpcchNodeName contains the number of
  440. characters stored in the buffer. The count returned does not include
  441. the terminating null character.
  442. lpszGroupName - Returns the name of the group that the resource is a member of.
  443. lpcchGroupName - Points to a variable that specifies the size, in characters,
  444. of the buffer pointed to by the lpszGroupName parameter. This size
  445. should include the terminating null character. When the function returns,
  446. the variable pointed to by lpcchGroupName contains the number of
  447. characters stored in the buffer. The count returned does not include
  448. the terminating null character.
  449. Return Value:
  450. Returns the resource's current state. Currently defined resource
  451. states include:
  452. ClusterResouceInitializing
  453. ClusterResouceOnline
  454. ClusterResouceOffline
  455. ClusterResouceFailed
  456. --*/
  457. {
  458. PCRESOURCE Resource;
  459. LPWSTR NodeName = NULL;
  460. LPWSTR GroupName = NULL;
  461. CLUSTER_RESOURCE_STATE State;
  462. DWORD Status;
  463. DWORD Length;
  464. Resource = (PCRESOURCE)hResource;
  465. WRAP(Status,
  466. (ApiGetResourceState(Resource->hResource,
  467. (LPDWORD)&State, // cast for win64 warning
  468. &NodeName,
  469. &GroupName)),
  470. Resource->Cluster);
  471. if (Status == ERROR_SUCCESS) {
  472. if (ARGUMENT_PRESENT(lpszNodeName)) {
  473. lstrcpynW(lpszNodeName, NodeName, *lpcchNodeName);
  474. Length = lstrlenW(NodeName);
  475. if (Length >= *lpcchNodeName) {
  476. Status = ERROR_MORE_DATA;
  477. State = ClusterResourceStateUnknown;
  478. }
  479. *lpcchNodeName = Length;
  480. }
  481. if (ARGUMENT_PRESENT(lpszGroupName)) {
  482. lstrcpynW(lpszGroupName, GroupName, *lpcchGroupName);
  483. Length = lstrlenW(GroupName);
  484. if (Length >= *lpcchGroupName) {
  485. Status = ERROR_MORE_DATA;
  486. State = ClusterResourceStateUnknown;
  487. }
  488. *lpcchGroupName = Length;
  489. }
  490. MIDL_user_free(NodeName);
  491. MIDL_user_free(GroupName);
  492. } else {
  493. State = ClusterResourceStateUnknown;
  494. }
  495. SetLastError( Status );
  496. return( State );
  497. }
  498. DWORD
  499. WINAPI
  500. SetClusterResourceName(
  501. IN HRESOURCE hResource,
  502. IN LPCWSTR lpszResourceName
  503. )
  504. /*++
  505. Routine Description:
  506. Sets the friendly name of a cluster resource
  507. Arguments:
  508. hResource - Supplies a handle to a cluster resource
  509. lpszResourceName - Supplies the new name of the cluster resource
  510. Return Value:
  511. ERROR_SUCCESS if successful
  512. Win32 error code otherwise
  513. --*/
  514. {
  515. PCRESOURCE Resource;
  516. DWORD Status;
  517. Resource = (PCRESOURCE)hResource;
  518. WRAP(Status,
  519. (ApiSetResourceName(Resource->hResource, lpszResourceName)),
  520. Resource->Cluster);
  521. return(Status);
  522. }
  523. DWORD
  524. WINAPI
  525. FailClusterResource(
  526. IN HRESOURCE hResource
  527. )
  528. /*++
  529. Routine Description:
  530. Initiates a resource failure. The specified resource is treated as failed.
  531. This causes the cluster to initiate the same failover process that would
  532. result if the resource actually failed.
  533. Arguments:
  534. hResource - Supplies a handle to the resource to be failed over
  535. Return Value:
  536. If the function succeeds, the return value is ERROR_SUCCESS.
  537. If the function fails, the return value is an error value.
  538. --*/
  539. {
  540. PCRESOURCE Resource;
  541. DWORD Status;
  542. Resource = (PCRESOURCE)hResource;
  543. WRAP(Status,
  544. (ApiFailResource(Resource->hResource)),
  545. Resource->Cluster);
  546. return(Status);
  547. }
  548. DWORD
  549. WINAPI
  550. OnlineClusterResource(
  551. IN HRESOURCE hResource
  552. )
  553. /*++
  554. Routine Description:
  555. Brings an offline resource online.
  556. If hDestinationNode is specified, but the resource is not capable
  557. of being brought online there, this API fails.
  558. If NULL is specified as the hDestinationNode, the best possible
  559. node is chosen by the cluster software.
  560. If NULL is specified but no node where this resource
  561. can be brought online is currently available, this API fails.
  562. Arguments:
  563. hResource - Supplies a handle to the resource to be failed over
  564. Return Value:
  565. If the function succeeds, the return value is ERROR_SUCCESS.
  566. If the function fails, the return value is an error value. If a suitable
  567. host node is not availabe, the error value is
  568. ERROR_HOST_NODE_NOT_AVAILABLE.
  569. --*/
  570. {
  571. PCRESOURCE Resource;
  572. DWORD Status;
  573. Resource = (PCRESOURCE)hResource;
  574. WRAP(Status,
  575. (ApiOnlineResource(Resource->hResource)),
  576. Resource->Cluster);
  577. return(Status);
  578. }
  579. DWORD
  580. WINAPI
  581. OfflineClusterResource(
  582. IN HRESOURCE hResource
  583. )
  584. /*++
  585. Routine Description:
  586. Brings an online resource offline.
  587. Arguments:
  588. hResource - Supplies a handle to the resource to be taken offline
  589. Return Value:
  590. If the function succeeds, the return value is ERROR_SUCCESS.
  591. If the function fails, the return value is an error value.
  592. --*/
  593. {
  594. PCRESOURCE Resource;
  595. DWORD Status;
  596. Resource = (PCRESOURCE)hResource;
  597. WRAP(Status,
  598. (ApiOfflineResource(Resource->hResource)),
  599. Resource->Cluster);
  600. return(Status);
  601. }
  602. DWORD
  603. WINAPI
  604. ChangeClusterResourceGroup(
  605. IN HRESOURCE hResource,
  606. IN HGROUP hGroup
  607. )
  608. /*++
  609. Routine Description:
  610. Moves a resource from one group to another.
  611. Arguments:
  612. hResource - Supplies the resource to be moved. If the resource
  613. depends on any other resources, those resources will also
  614. be moved. If other resources depend on the specified resource,
  615. those resources will also be moved.
  616. hGroup - Supplies the group that the resource should be moved into.
  617. If the resource is online, the specified group must be online
  618. on the same node.
  619. Return Value:
  620. If the function succeeds, the return value is ERROR_SUCCESS.
  621. If the function fails, the return value is an error value.
  622. --*/
  623. {
  624. PCRESOURCE Resource;
  625. DWORD Status;
  626. PCGROUP Group;
  627. Resource = (PCRESOURCE)hResource;
  628. Group = (PCGROUP)hGroup;
  629. WRAP(Status,
  630. (ApiChangeResourceGroup(Resource->hResource,Group->hGroup)),
  631. Resource->Cluster);
  632. return(Status);
  633. }
  634. DWORD
  635. WINAPI
  636. AddClusterResourceNode(
  637. IN HRESOURCE hResource,
  638. IN HNODE hNode
  639. )
  640. /*++
  641. Routine Description:
  642. Adds a node to the list of possible nodes that the specified
  643. resource can run on.
  644. Arguments:
  645. hResource - Supplies the resource whose list of potential host
  646. nodes is to be changed.
  647. hNode - Supplies the node which should be added to the resource's list of
  648. potential host nodes.
  649. Return Value:
  650. If the function succeeds, the return value is ERROR_SUCCESS.
  651. If the function fails, the return value is an error value.
  652. --*/
  653. {
  654. PCRESOURCE Resource = (PCRESOURCE)hResource;
  655. PCNODE Node = (PCNODE)hNode;
  656. DWORD Status;
  657. WRAP(Status,
  658. (ApiAddResourceNode(Resource->hResource, Node->hNode)),
  659. Resource->Cluster);
  660. return(Status);
  661. }
  662. DWORD
  663. WINAPI
  664. RemoveClusterResourceNode(
  665. IN HRESOURCE hResource,
  666. IN HNODE hNode
  667. )
  668. /*++
  669. Routine Description:
  670. Removes a node from the list of possible nodes that the specified
  671. resource can run on.
  672. Arguments:
  673. hResource - Supplies the resource whose list of potential host
  674. nodes is to be changed.
  675. hNode - Supplies the node which should be removed from the resource's
  676. list of potential host nodes.
  677. Return Value:
  678. If the function succeeds, the return value is ERROR_SUCCESS.
  679. If the function fails, the return value is an error value.
  680. --*/
  681. {
  682. PCRESOURCE Resource = (PCRESOURCE)hResource;
  683. PCNODE Node = (PCNODE)hNode;
  684. DWORD Status;
  685. WRAP(Status,
  686. (ApiRemoveResourceNode(Resource->hResource, Node->hNode)),
  687. Resource->Cluster);
  688. return(Status);
  689. }
  690. DWORD
  691. WINAPI
  692. AddClusterResourceDependency(
  693. IN HRESOURCE hResource,
  694. IN HRESOURCE hDependsOn
  695. )
  696. /*++
  697. Routine Description:
  698. Adds a dependency relationship between two resources.
  699. Arguments:
  700. hResource - Supplies the dependent resource.
  701. hDependsOn - Supplies the resource that hResource depends on.
  702. This resource must be in the same group as hResource. If
  703. hResource is currently online, this resource must also be
  704. currently online.
  705. Return Value:
  706. If the function succeeds, the return value is ERROR_SUCCESS.
  707. If the function fails, the return value is an error value.
  708. --*/
  709. {
  710. PCRESOURCE Resource;
  711. PCRESOURCE DependsOn;
  712. DWORD Status;
  713. Resource = (PCRESOURCE)hResource;
  714. DependsOn = (PCRESOURCE)hDependsOn;
  715. WRAP(Status,
  716. (ApiAddResourceDependency(Resource->hResource,DependsOn->hResource)),
  717. Resource->Cluster);
  718. return(Status);
  719. }
  720. DWORD
  721. WINAPI
  722. RemoveClusterResourceDependency(
  723. IN HRESOURCE hResource,
  724. IN HRESOURCE hDependsOn
  725. )
  726. /*++
  727. Routine Description:
  728. Removes a dependency relationship between two resources
  729. Arguments:
  730. hResource - Supplies the dependent resource
  731. hDependsOn - Supplies the resource that hResource is currently
  732. dependent on.
  733. Return Value:
  734. If the function succeeds, the return value is ERROR_SUCCESS.
  735. If the function fails, the return value is an error value.
  736. --*/
  737. {
  738. PCRESOURCE Resource;
  739. PCRESOURCE DependsOn;
  740. DWORD Status;
  741. Resource = (PCRESOURCE)hResource;
  742. DependsOn = (PCRESOURCE)hDependsOn;
  743. WRAP(Status,
  744. (ApiRemoveResourceDependency(Resource->hResource,DependsOn->hResource)),
  745. Resource->Cluster);
  746. return(Status);
  747. }
  748. BOOL
  749. WINAPI
  750. CanResourceBeDependent(
  751. IN HRESOURCE hResource,
  752. IN HRESOURCE hResourceDependent
  753. )
  754. /*++
  755. Routine Description:
  756. Determines if the resource identified by hResource can depend on hResourceDependent.
  757. In order for this to be true, both resources must be members of the same group and
  758. the resource identified by hResourceDependent cannot depend on the resource identified
  759. by hResource, whether directly or indirectly.
  760. Arguments:
  761. hResource - Supplies a handle to the resource to be dependent.
  762. hResourceDependent - Supplies a handle to the resource on which
  763. the resource identified by hResource can depend.
  764. Return Value:
  765. If the resource identified by hResource can depend on the resource
  766. identified by hResourceDependent, the return value is TRUE. Otherwise,
  767. the return value is FALSE.
  768. --*/
  769. {
  770. DWORD Status;
  771. PCRESOURCE Resource1 = (PCRESOURCE)hResource;
  772. PCRESOURCE Resource2 = (PCRESOURCE)hResourceDependent;
  773. WRAP(Status,
  774. (ApiCanResourceBeDependent(Resource1->hResource,Resource2->hResource)),
  775. Resource1->Cluster);
  776. if (Status == ERROR_SUCCESS) {
  777. return(TRUE);
  778. } else {
  779. return(FALSE);
  780. }
  781. }
  782. HRESENUM
  783. WINAPI
  784. ClusterResourceOpenEnum(
  785. IN HRESOURCE hResource,
  786. IN DWORD dwType
  787. )
  788. /*++
  789. Routine Description:
  790. Initiates an enumeration of a cluster resource's properties
  791. Arguments:
  792. hResource - Supplies a handle to the resource.
  793. dwType - Supplies a bitmask of the type of properties to be
  794. enumerated. Currently defined types include
  795. CLUSTER_RESOURCE_ENUM_DEPENDS - All resources the specified resource
  796. depends on.
  797. CLUSTER_RESOURCE_ENUM_PROVIDES - All resources that depend on the
  798. specified resource.
  799. CLUSTER_RESOURCE_ENUM_NODES - All nodes that this resource can run
  800. on.
  801. Return Value:
  802. If successful, returns a handle suitable for use with ClusterResourceEnum
  803. If unsuccessful, returns NULL and GetLastError() returns a more
  804. specific error code.
  805. --*/
  806. {
  807. PCRESOURCE Resource;
  808. PENUM_LIST Enum = NULL;
  809. DWORD Status;
  810. if ((dwType & CLUSTER_RESOURCE_ENUM_ALL) == 0) {
  811. SetLastError(ERROR_INVALID_PARAMETER);
  812. return(NULL);
  813. }
  814. if ((dwType & ~CLUSTER_RESOURCE_ENUM_ALL) != 0) {
  815. SetLastError(ERROR_INVALID_PARAMETER);
  816. return(NULL);
  817. }
  818. Resource = (PCRESOURCE)hResource;
  819. WRAP(Status,
  820. (ApiCreateResEnum(Resource->hResource,
  821. dwType,
  822. &Enum)),
  823. Resource->Cluster);
  824. if (Status != ERROR_SUCCESS) {
  825. SetLastError(Status);
  826. return(NULL);
  827. }
  828. return((HRESENUM)Enum);
  829. }
  830. DWORD
  831. WINAPI
  832. ClusterResourceGetEnumCount(
  833. IN HRESENUM hResEnum
  834. )
  835. /*++
  836. Routine Description:
  837. Gets the number of items contained the the enumerator's collection.
  838. Arguments:
  839. hEnum - a handle to an enumerator returned by ClusterResourceOpenEnum.
  840. Return Value:
  841. The number of items (possibly zero) in the enumerator's collection.
  842. --*/
  843. {
  844. PENUM_LIST Enum = (PENUM_LIST)hResEnum;
  845. return Enum->EntryCount;
  846. }
  847. DWORD
  848. WINAPI
  849. ClusterResourceEnum(
  850. IN HRESENUM hResEnum,
  851. IN DWORD dwIndex,
  852. OUT LPDWORD lpdwType,
  853. OUT LPWSTR lpszName,
  854. IN OUT LPDWORD lpcchName
  855. )
  856. /*++
  857. Routine Description:
  858. Returns the next enumerable resource property.
  859. Arguments:
  860. hResEnum - Supplies a handle to an open cluster resource enumeration
  861. returned by ClusterResourceOpenEnum
  862. dwIndex - Supplies the index to enumerate. This parameter should be
  863. zero for the first call to the ClusterResourceEnum function and
  864. then incremented for subsequent calls.
  865. dwType - Returns the type of property.
  866. lpszName - Points to a buffer that receives the name of the resource
  867. property, including the terminating null character.
  868. lpcchName - Points to a variable that specifies the size, in characters,
  869. of the buffer pointed to by the lpszName parameter. This size
  870. should include the terminating null character. When the function
  871. returns, the variable pointed to by lpcchName contains the
  872. number of characters stored in the buffer. The count returned
  873. does not include the terminating null character.
  874. Return Value:
  875. If the function succeeds, the return value is ERROR_SUCCESS.
  876. If the function fails, the return value is an error value.
  877. --*/
  878. {
  879. DWORD Status;
  880. DWORD NameLen;
  881. PENUM_LIST Enum = (PENUM_LIST)hResEnum;
  882. if (dwIndex >= Enum->EntryCount) {
  883. return(ERROR_NO_MORE_ITEMS);
  884. }
  885. NameLen = lstrlenW(Enum->Entry[dwIndex].Name);
  886. lstrcpynW(lpszName, Enum->Entry[dwIndex].Name, *lpcchName);
  887. if (*lpcchName < (NameLen + 1)) {
  888. if (lpszName == NULL) {
  889. Status = ERROR_SUCCESS;
  890. } else {
  891. Status = ERROR_MORE_DATA;
  892. }
  893. } else {
  894. Status = ERROR_SUCCESS;
  895. }
  896. *lpdwType = Enum->Entry[dwIndex].Type;
  897. *lpcchName = NameLen;
  898. return(Status);
  899. }
  900. DWORD
  901. WINAPI
  902. ClusterResourceCloseEnum(
  903. IN HRESENUM hResEnum
  904. )
  905. /*++
  906. Routine Description:
  907. Closes an open enumeration for a resource.
  908. Arguments:
  909. hResEnum - Supplies a handle to the enumeration to be closed.
  910. Return Value:
  911. If the function succeeds, the return value is ERROR_SUCCESS.
  912. If the function fails, the return value is an error value.
  913. --*/
  914. {
  915. DWORD i;
  916. PENUM_LIST Enum = (PENUM_LIST)hResEnum;
  917. //
  918. // Walk through enumeration freeing all the names
  919. //
  920. for (i=0; i<Enum->EntryCount; i++) {
  921. MIDL_user_free(Enum->Entry[i].Name);
  922. }
  923. MIDL_user_free(Enum);
  924. return(ERROR_SUCCESS);
  925. }
  926. DWORD
  927. WINAPI
  928. CreateClusterResourceType(
  929. IN HCLUSTER hCluster,
  930. IN LPCWSTR lpszTypeName,
  931. IN LPCWSTR lpszDisplayName,
  932. IN LPCWSTR lpszDllName,
  933. IN DWORD dwLooksAlive,
  934. IN DWORD dwIsAlive
  935. )
  936. /*++
  937. Routine Description:
  938. Creates a new resource type in the cluster. Note that this API only
  939. defines the resource type in the cluster registry and registers the
  940. resource type with the cluster service. The calling program is
  941. responsible for installing the resource type DLL on each node in the
  942. cluster.
  943. Arguments:
  944. hCluster - Supplies a handle to a previously opened cluster.
  945. lpszResourceTypeName - Supplies the new resource types name. The
  946. specified name must be unique within the cluster.
  947. lpszDisplayName - Supplies the display name for the new resource
  948. type. While lpszResourceTypeName should uniquely identify the
  949. resource type on all clusters, the lpszDisplayName should be
  950. a localized friendly name for the resource, suitable for displaying
  951. to administrators
  952. lpszResourceTypeDll - Supplies the name of the new resource types DLL.
  953. dwLooksAlivePollInterval - Supplies the default LooksAlive poll interval
  954. for the new resource type in milliseconds.
  955. dwIsAlivePollInterval - Supplies the default IsAlive poll interval for
  956. the new resource type in milliseconds.
  957. Return Value:
  958. ERROR_SUCCESS if successful
  959. Win32 error code otherwise
  960. --*/
  961. {
  962. PCLUSTER Cluster;
  963. error_status_t Status = ERROR_SUCCESS;
  964. Cluster = (PCLUSTER)hCluster;
  965. WRAP(Status,
  966. (ApiCreateResourceType(Cluster->RpcBinding,
  967. lpszTypeName,
  968. lpszDisplayName,
  969. lpszDllName,
  970. dwLooksAlive,
  971. dwIsAlive)),
  972. Cluster);
  973. return(Status);
  974. }
  975. DWORD
  976. WINAPI
  977. DeleteClusterResourceType(
  978. IN HCLUSTER hCluster,
  979. IN LPCWSTR lpszTypeName
  980. )
  981. /*++
  982. Routine Description:
  983. Deletes a resource type in the cluster. Note that this API only
  984. deletes the resource type in the cluster registry and unregisters the
  985. resource type with the cluster service. The calling program is
  986. responsible for deleting the resource type DLL on each node in the
  987. cluster. If any resources of the specified type exist, this API
  988. fails. The calling program is responsible for deleting any resources
  989. of this type before deleting the resource type.
  990. Arguments:
  991. hCluster - Supplies a handle to a previously opened cluster.
  992. lpszResourceTypeName - Supplies the name of the resource type to
  993. be deleted.
  994. Return Value:
  995. ERROR_SUCCESS if successful
  996. Win32 error code otherwise
  997. --*/
  998. {
  999. PCLUSTER Cluster;
  1000. error_status_t Status = ERROR_SUCCESS;
  1001. Cluster = (PCLUSTER)hCluster;
  1002. WRAP(Status,
  1003. (ApiDeleteResourceType(Cluster->RpcBinding,lpszTypeName)),
  1004. Cluster);
  1005. return(Status);
  1006. }
  1007. /****
  1008. @func HRESTYPEENUM | ClusterResourceTypeOpenEnum | Initiates
  1009. an enumeration of a cluster resource type's properties.
  1010. @parm IN HCLUSTER | hCluster | Handle to the cluster
  1011. @parm IN LPCWSTR | lpszResourceTypeName | Pointer to the name of the
  1012. resource type
  1013. @parm IN DWORD | dwType | A bitmask of the type of properties
  1014. to be enumerated. Currently, the only defined type is
  1015. CLUSTER_RESOURCE_TYPE_ENUM_NODES.
  1016. @comm This function opens an enumerator for iterating through
  1017. a resource type's nodes
  1018. @rdesc Returns NULL if the operation is unsuccessful. For
  1019. detailed information about the error, call the Win32
  1020. function GetLastError (). A handle to the enumeration
  1021. on success.
  1022. @xref <f ClusterResourceTypeEnum> <f ClusterResourceTypeCloseEnum>
  1023. ****/
  1024. HRESTYPEENUM
  1025. WINAPI
  1026. ClusterResourceTypeOpenEnum(
  1027. IN HCLUSTER hCluster,
  1028. IN LPCWSTR lpszResourceTypeName,
  1029. IN DWORD dwType
  1030. )
  1031. {
  1032. PCLUSTER pCluster;
  1033. PENUM_LIST Enum = NULL;
  1034. DWORD Status;
  1035. pCluster = (PCLUSTER)hCluster;
  1036. if ((dwType & CLUSTER_RESOURCE_TYPE_ENUM_ALL) == 0) {
  1037. Status = ERROR_INVALID_PARAMETER;
  1038. goto error_exit;
  1039. }
  1040. if ((dwType & ~CLUSTER_RESOURCE_TYPE_ENUM_ALL) != 0) {
  1041. Status = ERROR_INVALID_PARAMETER;
  1042. goto error_exit;
  1043. }
  1044. WRAP(Status,
  1045. (ApiCreateResTypeEnum(pCluster->RpcBinding,
  1046. lpszResourceTypeName,
  1047. dwType,
  1048. &Enum)),
  1049. pCluster);
  1050. if (Status == RPC_S_PROCNUM_OUT_OF_RANGE) {
  1051. //
  1052. // The current node is NT4Sp4 or lower. Try
  1053. // some other node in the cluster
  1054. //
  1055. TIME_PRINT(("ClusterResourceTypeOpenEnum - Current Cluster Node is NTSp4 or lower !!!\n"));
  1056. TIME_PRINT(("ClusterResourceTypeOpenEnum - Trying some other candidate ...\n"));
  1057. Enum = (PENUM_LIST)ClusterResourceTypeOpenEnumFromCandidate(hCluster,
  1058. lpszResourceTypeName,
  1059. dwType);
  1060. if (Enum == NULL)
  1061. {
  1062. //
  1063. // Did not find a node NT4Sp5 or higher AND at least
  1064. // one node is down. Can't enumerate.
  1065. //
  1066. TIME_PRINT(("ClusterResourceTypeOpenEnum - ClusterResourceTypeOpenEnumFromCandidate failed !!!\n"));
  1067. Status = GetLastError ();
  1068. goto error_exit;
  1069. }
  1070. Status = ERROR_SUCCESS;
  1071. }
  1072. if (Status != ERROR_SUCCESS) {
  1073. goto error_exit;
  1074. }
  1075. return((HRESTYPEENUM)Enum);
  1076. error_exit:
  1077. SetLastError(Status);
  1078. return(NULL);
  1079. }
  1080. DWORD
  1081. WINAPI
  1082. ClusterResourceTypeGetEnumCount(
  1083. IN HRESTYPEENUM hResTypeEnum
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Gets the number of items contained the the enumerator's collection.
  1088. Arguments:
  1089. hEnum - a handle to an enumerator returned by ClusterResourceTypeOpenEnum.
  1090. Return Value:
  1091. The number of items (possibly zero) in the enumerator's collection.
  1092. --*/
  1093. {
  1094. PENUM_LIST Enum = (PENUM_LIST)hResTypeEnum;
  1095. return Enum->EntryCount;
  1096. }
  1097. /****
  1098. @func DWORD | ClusterResourceTypeEnum | Enumerates a resource
  1099. type's nodes, returning the name of one object per call.
  1100. @parm IN HRESTYPEENUM | hResTypeEnum | Supplies a handle to
  1101. an open cluster resource enumeration returned by
  1102. ClusterResourceTypeOpenEnum.
  1103. @parm IN DWORD | dwIndex | Supplies the index to enumerate.
  1104. This parameter should be zero for the first call
  1105. to the ClusterResourceTypeEnum function and
  1106. then incremented for subsequent calls.
  1107. @parm OUT DWORD | lpdwType | Returns the type of property.
  1108. Currently, the only defined type is
  1109. CLUSTER_RESOURCE_TYPE_ENUM_NODES.
  1110. @parm OUT LPWSTR | lpszName | Points to a buffer that
  1111. receives the name of the resource type.
  1112. @parm IN OUT LPDWORD | lpcchName | Points to a variable that
  1113. specifies the size, in characters, of the buffer
  1114. pointed to by the lpszName parameter. This size
  1115. should include the terminating null character.
  1116. When the function returns, the variable pointed
  1117. to by lpcchName contains the number of characters
  1118. stored in the buffer. The count returned
  1119. does not include the terminating null character.
  1120. property, including the terminating null character.
  1121. @comm This function opens an enumerator for iterating through
  1122. a resource type's nodes.
  1123. @rdesc Returns a Win32 error code if the operation is
  1124. unsuccessful. ERROR_SUCCESS on success.
  1125. @xref <f ClusterResourceTypeOpenEnum> <f ClusterResourceTypeCloseEnum>
  1126. ****/
  1127. DWORD
  1128. WINAPI
  1129. ClusterResourceTypeEnum(
  1130. IN HRESTYPEENUM hResTypeEnum,
  1131. IN DWORD dwIndex,
  1132. OUT LPDWORD lpdwType,
  1133. OUT LPWSTR lpszName,
  1134. IN OUT LPDWORD lpcchName
  1135. )
  1136. {
  1137. DWORD Status;
  1138. DWORD NameLen;
  1139. PENUM_LIST Enum = (PENUM_LIST)hResTypeEnum;
  1140. if ((Enum == NULL) ||
  1141. (lpcchName == NULL) ||
  1142. (lpdwType == NULL)) {
  1143. Status = ERROR_INVALID_PARAMETER;
  1144. goto error_exit;
  1145. }
  1146. if (dwIndex >= Enum->EntryCount) {
  1147. Status = ERROR_NO_MORE_ITEMS;
  1148. goto error_exit;
  1149. }
  1150. NameLen = lstrlenW(Enum->Entry[dwIndex].Name);
  1151. lstrcpynW(lpszName, Enum->Entry[dwIndex].Name, *lpcchName);
  1152. if (*lpcchName < (NameLen + 1)) {
  1153. if (lpszName == NULL) {
  1154. Status = ERROR_SUCCESS;
  1155. } else {
  1156. Status = ERROR_MORE_DATA;
  1157. }
  1158. } else {
  1159. Status = ERROR_SUCCESS;
  1160. }
  1161. *lpdwType = Enum->Entry[dwIndex].Type;
  1162. *lpcchName = NameLen;
  1163. error_exit:
  1164. return(Status);
  1165. }
  1166. /****
  1167. @func DWORD | ClusterResourceTypeCloseEnum | Closes an open
  1168. enumeration for a resource type.
  1169. @parm IN HRESTYPEENUM | hResTypeEnum | Handle to the
  1170. enumeration to be closed.
  1171. @comm This function closes an open enumeration.
  1172. @rdesc Returns ERROR_SUCCESS on success. A Win32 error code otherwise.
  1173. @xref <f ClusterResourceTypeEnum> <f ClusterResourceTypeOpenEnum>
  1174. ****/
  1175. DWORD
  1176. WINAPI
  1177. ClusterResourceTypeCloseEnum(
  1178. IN HRESTYPEENUM hResTypeEnum
  1179. )
  1180. {
  1181. DWORD i;
  1182. PENUM_LIST Enum = (PENUM_LIST)hResTypeEnum;
  1183. DWORD Status;
  1184. if (Enum == NULL) {
  1185. Status = ERROR_INVALID_PARAMETER;
  1186. goto error_exit;
  1187. }
  1188. //
  1189. // Walk through enumeration freeing all the names
  1190. //
  1191. for (i=0; i<Enum->EntryCount; i++) {
  1192. MIDL_user_free(Enum->Entry[i].Name);
  1193. }
  1194. MIDL_user_free(Enum);
  1195. Status = ERROR_SUCCESS;
  1196. error_exit:
  1197. return(Status);
  1198. }
  1199. BOOL
  1200. WINAPI
  1201. GetClusterResourceNetworkName(
  1202. IN HRESOURCE hResource,
  1203. OUT LPWSTR lpBuffer,
  1204. IN OUT LPDWORD nSize
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. Enumerates the dependencies of a resource in an attempt to find
  1209. a network name that the resource depends on. If a network name
  1210. is found, this function returns TRUE and fills in lpBuffer with
  1211. the network name. If a network name is not found, this function
  1212. returns FALSE.
  1213. Arguments:
  1214. hResource - Supplies the resource.
  1215. lpBuffer - Points to a buffer to receive the null-terminated character
  1216. string containing the network name.
  1217. nSize - Points to a variable that specifies the maximum size, in characters,
  1218. of the buffer. This value should be large enough to contain
  1219. MAX_COMPUTERNAME_LENGTH + 1 characters.
  1220. Return Value:
  1221. TRUE if successful
  1222. FALSE if unsuccessful
  1223. --*/
  1224. {
  1225. BOOL Success;
  1226. PCRESOURCE Resource = (PCRESOURCE)hResource;
  1227. //
  1228. // Call a recursive worker to do the search.
  1229. //
  1230. Success = FindNetworkWorker(Resource->hResource,
  1231. Resource->Cluster,
  1232. lpBuffer,
  1233. nSize);
  1234. return(Success);
  1235. }
  1236. BOOL
  1237. FindNetworkWorker(
  1238. IN HRES_RPC hResource,
  1239. IN PCLUSTER Cluster,
  1240. OUT LPWSTR lpBuffer,
  1241. IN OUT LPDWORD nSize
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. Recursive worker to search a resource's dependency tree
  1246. for a network name resource.
  1247. Arguments:
  1248. Resource - Supplies the resource.
  1249. Cluster - Supplies the cluster.
  1250. lpBuffer - Points to a buffer to receive the null-terminated character
  1251. string containing the network name.
  1252. nSize - Points to a variable that specifies the maximum size, in characters,
  1253. of the buffer. This value should be large enough to contain
  1254. MAX_COMPUTERNAME_LENGTH + 1 characters.
  1255. Return Value:
  1256. TRUE if successful
  1257. FALSE if unsuccessful
  1258. --*/
  1259. {
  1260. BOOL Success = FALSE;
  1261. DWORD i;
  1262. PENUM_LIST Enum=NULL;
  1263. DWORD Status;
  1264. HRES_RPC hRes;
  1265. LPWSTR TypeName;
  1266. //
  1267. // Create a dependency enumeration
  1268. //
  1269. WRAP(Status,
  1270. (ApiCreateResEnum(hResource,
  1271. CLUSTER_RESOURCE_ENUM_DEPENDS,
  1272. &Enum)),
  1273. Cluster);
  1274. if (Status != ERROR_SUCCESS) {
  1275. SetLastError(Status);
  1276. return(FALSE);
  1277. }
  1278. //
  1279. // Open each resource in the dependency and see if it is a network name
  1280. // resource.
  1281. //
  1282. for (i=0; i<Enum->EntryCount; i++) {
  1283. WRAP_NULL(hRes,
  1284. (ApiOpenResource(Cluster->RpcBinding,
  1285. Enum->Entry[i].Name,
  1286. &Status)),
  1287. &Status,
  1288. Cluster);
  1289. if (hRes != NULL) {
  1290. TypeName = NULL;
  1291. WRAP(Status,
  1292. (ApiGetResourceType(hRes,
  1293. &TypeName)),
  1294. Cluster);
  1295. if (Status == ERROR_SUCCESS) {
  1296. //
  1297. // See if this type name matches.
  1298. //
  1299. if (lstrcmpiW(TypeName, CLUS_RESTYPE_NAME_NETNAME) == 0) {
  1300. HRESOURCE NetResource;
  1301. HKEY NetKey;
  1302. HKEY NetParamKey;
  1303. //
  1304. // We have a match, pull out the Name parameter.
  1305. // Go ahead and really open the resource so we
  1306. // can use the registry functions on it.
  1307. //
  1308. NetResource = OpenClusterResource((HCLUSTER)Cluster,
  1309. Enum->Entry[i].Name);
  1310. if (NetResource != NULL) {
  1311. NetKey = GetClusterResourceKey(NetResource, KEY_READ);
  1312. CloseClusterResource(NetResource);
  1313. if (NetKey != NULL) {
  1314. Status = ClusterRegOpenKey(NetKey,
  1315. CLUSREG_KEYNAME_PARAMETERS,
  1316. KEY_READ,
  1317. &NetParamKey);
  1318. ClusterRegCloseKey(NetKey);
  1319. if (Status == ERROR_SUCCESS) {
  1320. DWORD cbData;
  1321. cbData = *nSize * sizeof(WCHAR);
  1322. Status = ClusterRegQueryValue(NetParamKey,
  1323. CLUSREG_NAME_RES_NAME,
  1324. NULL,
  1325. (LPBYTE)lpBuffer,
  1326. &cbData);
  1327. ClusterRegCloseKey(NetParamKey);
  1328. if (Status == ERROR_SUCCESS) {
  1329. Success = TRUE;
  1330. *nSize = wcslen(lpBuffer);
  1331. }
  1332. }
  1333. }
  1334. }
  1335. } else {
  1336. //
  1337. // Try the dependents of this resource
  1338. //
  1339. Success = FindNetworkWorker(hRes,
  1340. Cluster,
  1341. lpBuffer,
  1342. nSize);
  1343. }
  1344. MIDL_user_free(TypeName);
  1345. }
  1346. ApiCloseResource(&hRes);
  1347. if (Success) {
  1348. break;
  1349. }
  1350. }
  1351. }
  1352. if (!Success && (Status == ERROR_SUCCESS)) {
  1353. Status = ERROR_DEPENDENCY_NOT_FOUND;
  1354. }
  1355. if (Status != ERROR_SUCCESS) {
  1356. SetLastError(Status);
  1357. }
  1358. MIDL_user_free(Enum);
  1359. return(Success);
  1360. }
  1361. HCLUSTER
  1362. WINAPI
  1363. GetClusterFromResource(
  1364. IN HRESOURCE hResource
  1365. )
  1366. /*++
  1367. Routine Description:
  1368. Returns the cluster handle from the associated resource handle.
  1369. Arguments:
  1370. hResource - Supplies the resource.
  1371. Return Value:
  1372. Handle to the cluster associated with the resource handle.
  1373. --*/
  1374. {
  1375. DWORD nStatus;
  1376. PCRESOURCE Resource = (PCRESOURCE)hResource;
  1377. HCLUSTER hCluster = (HCLUSTER)Resource->Cluster;
  1378. nStatus = AddRefToClusterHandle( hCluster );
  1379. if ( nStatus != ERROR_SUCCESS ) {
  1380. SetLastError( nStatus );
  1381. hCluster = NULL;
  1382. }
  1383. return( hCluster );
  1384. } // GetClusterFromResource()