1840 lines
46 KiB
C
1840 lines
46 KiB
C
/*++
|
||
|
||
Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
resrcapi.c
|
||
|
||
Abstract:
|
||
|
||
Public interfaces for managing cluster resources.
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 15-Jan-1996
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "clusapip.h"
|
||
|
||
//
|
||
// Local function prototypes
|
||
//
|
||
HRESOURCE
|
||
InitClusterResource(
|
||
IN HRES_RPC hResource,
|
||
IN LPCWSTR lpszResourceName,
|
||
IN PCLUSTER pCluster
|
||
);
|
||
|
||
HRESTYPEENUM
|
||
ClusterResourceTypeOpenEnumFromCandidate(
|
||
IN HCLUSTER hCluster,
|
||
IN LPCWSTR lpszResourceTypeName,
|
||
IN DWORD dwType
|
||
);
|
||
|
||
|
||
BOOL
|
||
FindNetworkWorker(
|
||
IN HRES_RPC hResource,
|
||
IN PCLUSTER Cluster,
|
||
OUT LPWSTR lpBuffer,
|
||
IN OUT LPDWORD nSize
|
||
);
|
||
|
||
|
||
/****
|
||
@func DWORD | ClusterResourceTypeOpenEnumFromCandidate | Tries to
|
||
enumerate the nodes that support a resource type
|
||
using a candidate node in the cluster
|
||
|
||
@parm IN HCLUSTER | hCluster | Handle to the cluster
|
||
@parm IN LPCWSTR | lpszResourceTypeName | Pointer to the name of the
|
||
resource type
|
||
@parm IN DWORD | dwType | A bitmask of the type of properties
|
||
to be enumerated. Currently, the only defined type is
|
||
CLUSTER_RESOURCE_TYPE_ENUM_NODES.
|
||
|
||
@rdesc Returns NULL if the operation is unsuccessful. For
|
||
detailed information about the error, call the Win32
|
||
function GetLastError (). A handle to the enumeration
|
||
on success.
|
||
|
||
@xref <f ClusterResourceTypeOpenEnum>
|
||
****/
|
||
|
||
HRESTYPEENUM
|
||
ClusterResourceTypeOpenEnumFromCandidate(
|
||
IN HCLUSTER hCluster,
|
||
IN LPCWSTR lpszResourceTypeName,
|
||
IN DWORD dwType
|
||
)
|
||
{
|
||
DWORD dwError = ERROR_SUCCESS;
|
||
DWORD dwEnumType;
|
||
HCLUSENUM hNodeEnum = 0;
|
||
WCHAR NameBuf[50];
|
||
DWORD NameLen, i, j;
|
||
HCLUSTER hClusNode;
|
||
PCLUSTER pClus;
|
||
BOOL bFoundSp5OrHigherNode = FALSE;
|
||
PENUM_LIST Enum = NULL;
|
||
BOOL bNodeDown = FALSE;
|
||
|
||
//
|
||
// Open node enumeration in the cluster
|
||
//
|
||
hNodeEnum = ClusterOpenEnum(hCluster, CLUSTER_ENUM_NODE);
|
||
if (hNodeEnum == NULL) {
|
||
dwError = GetLastError();
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnum - ClusterOpenEnum failed %d\n",
|
||
dwError));
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Enumerate the nodes in the cluster. If you find a live node
|
||
// that is NT4Sp5 or higher, try to enumerate the resource types
|
||
// from that node
|
||
//
|
||
for (i=0; ; i++) {
|
||
dwError = ERROR_SUCCESS;
|
||
|
||
NameLen = sizeof(NameBuf)/sizeof(WCHAR);
|
||
dwError = ClusterEnum(hNodeEnum, i, &dwEnumType, NameBuf, &NameLen);
|
||
if (dwError == ERROR_NO_MORE_ITEMS) {
|
||
dwError = ERROR_SUCCESS;
|
||
break;
|
||
} else if (dwError != ERROR_SUCCESS) {
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - ClusterEnum %d returned error %d\n",
|
||
i,dwError));
|
||
goto error_exit;
|
||
}
|
||
|
||
if (dwEnumType != CLUSTER_ENUM_NODE) {
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Invalid Type %d returned from ClusterEnum\n",
|
||
dwEnumType));
|
||
goto error_exit;
|
||
}
|
||
|
||
hClusNode = OpenCluster(NameBuf);
|
||
if (hClusNode == NULL) {
|
||
bNodeDown = TRUE;
|
||
dwError = GetLastError();
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - OpenCluster %ws failed %d\n",
|
||
NameBuf, dwError));
|
||
continue;
|
||
}
|
||
|
||
pClus = GET_CLUSTER(hClusNode);
|
||
|
||
dwError = ApiCreateResTypeEnum(pClus->RpcBinding,
|
||
lpszResourceTypeName,
|
||
dwType,
|
||
&Enum);
|
||
|
||
if (!CloseCluster(hClusNode)) {
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - CloseCluster %ws failed %d\n",
|
||
NameBuf, GetLastError()));
|
||
}
|
||
|
||
if (dwError == RPC_S_PROCNUM_OUT_OF_RANGE) {
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Node %ws is also NT4Sp3/Sp4, skipping...\n",
|
||
NameBuf));
|
||
dwError = ERROR_SUCCESS;
|
||
continue;
|
||
} else if ((dwError == ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND) ||
|
||
(dwError == ERROR_INVALID_PARAMETER) ||
|
||
(dwError == ERROR_NOT_ENOUGH_MEMORY)) {
|
||
//
|
||
// The above three error codes returned by the RPC
|
||
// are fatal and so it is not wise to continue any further.
|
||
//
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - ApiCreateResTypeEnum fatally failed %d at node %ws\n",
|
||
dwError,NameBuf));
|
||
goto error_exit;
|
||
}
|
||
else if (dwError != ERROR_SUCCESS) {
|
||
bNodeDown = TRUE;
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - ApiCreateResTypeEnum failed %d (Node %ws down possibly)\n",
|
||
dwError,NameBuf));
|
||
continue;
|
||
}
|
||
else {
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Found node %ws NT4Sp5 or higher\n",
|
||
NameBuf));
|
||
bFoundSp5OrHigherNode = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!bFoundSp5OrHigherNode) {
|
||
//
|
||
// Did not find a node higher than NT4Sp4.
|
||
//
|
||
if (!bNodeDown) {
|
||
//
|
||
// Assume all nodes are NT4Sp3/Sp4. Send the open node enumeration
|
||
// back to the client since we assume NT4Sp3/Sp4 supports
|
||
// all resource types. The client is responsible for closing
|
||
// the open node enumeration. Note that before a handle to
|
||
// the enumeration is returned back, we need to fake the type
|
||
// of enumeration.
|
||
//
|
||
// Chittur Subbaraman (chitturs) - 09/08/98
|
||
//
|
||
// How do we know that the resource type parameter
|
||
// in this case is a valid one ?
|
||
//
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Assuming all nodes are NT4Sp3 ...\n"));
|
||
Enum = (PENUM_LIST)hNodeEnum;
|
||
for (j=0; j<i; j++) {
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Faking type ...\n"));
|
||
Enum->Entry[j].Type = CLUSTER_RESOURCE_TYPE_ENUM_NODES;
|
||
}
|
||
} else {
|
||
//
|
||
// Atleast 1 node was unreachable. Can't enumerate properly.
|
||
//
|
||
dwError = ERROR_NODE_NOT_AVAILABLE;
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - At least 1 node in this mixed mode/Sp3/Sp4 cluster is down ...\n"));
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnumFromCandidate - Can't enumerate properly !!!\n"));
|
||
goto error_exit;
|
||
}
|
||
} else {
|
||
ClusterCloseEnum(hNodeEnum);
|
||
}
|
||
return((HRESTYPEENUM)Enum);
|
||
|
||
error_exit:
|
||
if (hNodeEnum != NULL) {
|
||
ClusterCloseEnum(hNodeEnum);
|
||
}
|
||
SetLastError(dwError);
|
||
return(NULL);
|
||
}
|
||
|
||
HRESOURCE
|
||
InitClusterResource(
|
||
IN HRES_RPC hResource,
|
||
IN LPCWSTR lpszResourceName,
|
||
IN PCLUSTER pCluster
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates and initializes a CRESOURCE. The initialized CRESOURCE
|
||
is linked onto the cluster structure.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the RPC resource handle.
|
||
|
||
lpszResourceName - Supplies the name of the resource.
|
||
|
||
pCluster - Supplies the cluster
|
||
|
||
Return Value:
|
||
|
||
A pointer to the initialized CRESOURCE structure.
|
||
|
||
NULL on error.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
|
||
Resource = LocalAlloc(LMEM_FIXED, sizeof(CRESOURCE));
|
||
if (Resource == NULL) {
|
||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
return(NULL);
|
||
}
|
||
Resource->Name = LocalAlloc(LMEM_FIXED, (lstrlenW(lpszResourceName)+1)*sizeof(WCHAR));
|
||
if (Resource->Name == NULL) {
|
||
LocalFree(Resource);
|
||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
return(NULL);
|
||
}
|
||
lstrcpyW(Resource->Name, lpszResourceName);
|
||
Resource->Cluster = pCluster;
|
||
Resource->hResource = hResource;
|
||
InitializeListHead(&Resource->NotifyList);
|
||
|
||
//
|
||
// Link new resource onto the cluster structure.
|
||
//
|
||
EnterCriticalSection(&pCluster->Lock);
|
||
InsertHeadList(&pCluster->ResourceList, &Resource->ListEntry);
|
||
LeaveCriticalSection(&pCluster->Lock);
|
||
|
||
return ((HRESOURCE)Resource);
|
||
|
||
}
|
||
|
||
|
||
|
||
HRESOURCE
|
||
WINAPI
|
||
CreateClusterResource(
|
||
IN HGROUP hGroup,
|
||
IN LPCWSTR lpszResourceName,
|
||
IN LPCWSTR lpszResourceType,
|
||
IN DWORD dwFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a new resource in the cluster.
|
||
|
||
Arguments:
|
||
hGroup - Supplies a handle to the group that the resource should be
|
||
created in.
|
||
|
||
lpszResourceName - Supplies the new resource's name. The specified name
|
||
must be unique within the cluster.
|
||
|
||
lpszResourceType - Supplies the new resource<63>s type. The specified
|
||
resource type must be installed in the cluster.
|
||
|
||
dwFlags - Supplies optional flags. Currently defined flags are:
|
||
CLUSTER_RESOURCE_SEPARATE_MONITOR - This resource should be created
|
||
in a separate resource monitor instead of the shared resource monitor.
|
||
|
||
|
||
Return Value:
|
||
|
||
non-NULL - returns an open handle to the specified cluster.
|
||
|
||
NULL - The operation failed. Extended error status is available
|
||
using GetLastError()
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESOURCE Resource;
|
||
HRES_RPC hRes;
|
||
PCGROUP Group;
|
||
error_status_t Status = ERROR_SUCCESS;
|
||
|
||
Group = (PCGROUP)hGroup;
|
||
WRAP_NULL(hRes,
|
||
(ApiCreateResource(Group->hGroup,
|
||
lpszResourceName,
|
||
lpszResourceType,
|
||
dwFlags,
|
||
&Status)),
|
||
&Status,
|
||
Group->Cluster);
|
||
|
||
if (hRes == NULL) {
|
||
SetLastError(Status);
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Initialize the newly created resource and return
|
||
// the HRESOURCE.
|
||
//
|
||
Resource = InitClusterResource(hRes, lpszResourceName, Group->Cluster);
|
||
if (Resource == NULL) {
|
||
Status = GetLastError();
|
||
ApiCloseResource(&hRes);
|
||
SetLastError(Status);
|
||
}
|
||
return(Resource);
|
||
}
|
||
|
||
|
||
HRESOURCE
|
||
WINAPI
|
||
OpenClusterResource(
|
||
IN HCLUSTER hCluster,
|
||
IN LPCWSTR lpszResourceName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens a handle to the specified resource
|
||
|
||
Arguments:
|
||
|
||
hCluster - Supplies a handle to the cluster
|
||
|
||
lpszResourceName - Supplies the name of the resource to be opened
|
||
|
||
Return Value:
|
||
|
||
non-NULL - returns an open handle to the specified cluster.
|
||
|
||
NULL - The operation failed. Extended error status is available
|
||
using GetLastError()
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESOURCE Resource;
|
||
HRES_RPC hRes;
|
||
error_status_t Status = ERROR_SUCCESS;
|
||
PCLUSTER Cluster = (PCLUSTER)hCluster;
|
||
|
||
WRAP_NULL(hRes,
|
||
(ApiOpenResource(Cluster->RpcBinding,
|
||
lpszResourceName,
|
||
&Status)),
|
||
&Status,
|
||
Cluster);
|
||
|
||
if ((hRes == NULL) || (Status != ERROR_SUCCESS)) {
|
||
SetLastError(Status);
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Initialize the newly created resource and return
|
||
// the HRESOURCE.
|
||
//
|
||
Resource = InitClusterResource(hRes, lpszResourceName, Cluster);
|
||
if (Resource == NULL) {
|
||
Status = GetLastError();
|
||
ApiCloseResource(&hRes);
|
||
SetLastError(Status);
|
||
}
|
||
return(Resource);
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
CloseClusterResource(
|
||
IN HRESOURCE hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Closes a resource handle returned from OpenClusterResource
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource handle
|
||
|
||
Return Value:
|
||
|
||
TRUE - The operation was successful.
|
||
|
||
FALSE - The operation failed. Extended error status is available
|
||
using GetLastError()
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
PCLUSTER Cluster;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
Cluster = (PCLUSTER)Resource->Cluster;
|
||
|
||
//
|
||
// Unlink resource from cluster list.
|
||
//
|
||
EnterCriticalSection(&Cluster->Lock);
|
||
RemoveEntryList(&Resource->ListEntry);
|
||
|
||
//
|
||
// Remove any notifications posted against this resource.
|
||
//
|
||
RundownNotifyEvents(&Resource->NotifyList, Resource->Name);
|
||
|
||
//if the cluster is dead and the reconnect has failed,
|
||
//the Resource->hResource might be NULL if s_apiopenresource for
|
||
//this group failed on a reconnect
|
||
//the cluster may be dead and hresource may be non null, say
|
||
//if reconnectgroups succeeded but the reconnect resources
|
||
//failed
|
||
//At reconnect, the old context is saved in the obsolete
|
||
//list for deletion when the cluster handle is closed or
|
||
//when the next api call is made
|
||
if ((Cluster->Flags & CLUS_DEAD) && (Resource->hResource))
|
||
{
|
||
RpcSmDestroyClientContext(&Resource->hResource);
|
||
LeaveCriticalSection(&Cluster->Lock);
|
||
goto FnExit;
|
||
}
|
||
|
||
LeaveCriticalSection(&Cluster->Lock);
|
||
|
||
// Close RPC context handle
|
||
//
|
||
ApiCloseResource(&Resource->hResource);
|
||
|
||
FnExit:
|
||
//
|
||
// Free memory allocations
|
||
//
|
||
LocalFree(Resource->Name);
|
||
LocalFree(Resource);
|
||
|
||
//
|
||
// Give the cluster a chance to clean up in case this
|
||
// resource was the only thing keeping it around.
|
||
//
|
||
CleanupCluster(Cluster);
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DeleteClusterResource(
|
||
IN HRESOURCE hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Permanently deletes a resource from the cluster.
|
||
The specified resource must be offline.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource to be deleted
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
If the resource is not currently offline, the error value
|
||
is ERROR_RESOURCE_NOT_OFFLINE.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
|
||
WRAP(Status,
|
||
(ApiDeleteResource(Resource->hResource)),
|
||
Resource->Cluster);
|
||
|
||
return(Status);
|
||
|
||
}
|
||
|
||
|
||
CLUSTER_RESOURCE_STATE
|
||
WINAPI
|
||
GetClusterResourceState(
|
||
IN HRESOURCE hResource,
|
||
OUT OPTIONAL LPWSTR lpszNodeName,
|
||
IN OUT LPDWORD lpcchNodeName,
|
||
OUT OPTIONAL LPWSTR lpszGroupName,
|
||
IN OUT LPDWORD lpcchGroupName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the resource's current state and the node where
|
||
it is currently online.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to a cluster resource
|
||
|
||
lpszNodeName - Returns the name of the node in the cluster where the
|
||
given resource is currently online
|
||
|
||
lpcchNodeName - Points to a variable that specifies the size, in characters,
|
||
of the buffer pointed to by the lpszNodeName parameter. This size
|
||
should include the terminating null character. When the function returns,
|
||
the variable pointed to by lpcchNodeName contains the number of
|
||
characters stored in the buffer. The count returned does not include
|
||
the terminating null character.
|
||
|
||
lpszGroupName - Returns the name of the group that the resource is a member of.
|
||
|
||
lpcchGroupName - Points to a variable that specifies the size, in characters,
|
||
of the buffer pointed to by the lpszGroupName parameter. This size
|
||
should include the terminating null character. When the function returns,
|
||
the variable pointed to by lpcchGroupName contains the number of
|
||
characters stored in the buffer. The count returned does not include
|
||
the terminating null character.
|
||
|
||
Return Value:
|
||
|
||
Returns the resource's current state. Currently defined resource
|
||
states include:
|
||
|
||
ClusterResouceInitializing
|
||
ClusterResouceOnline
|
||
ClusterResouceOffline
|
||
ClusterResouceFailed
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
LPWSTR NodeName = NULL;
|
||
LPWSTR GroupName = NULL;
|
||
CLUSTER_RESOURCE_STATE State;
|
||
DWORD Status;
|
||
DWORD Length;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
WRAP(Status,
|
||
(ApiGetResourceState(Resource->hResource,
|
||
(LPDWORD)&State, // cast for win64 warning
|
||
&NodeName,
|
||
&GroupName)),
|
||
Resource->Cluster);
|
||
if (Status == ERROR_SUCCESS) {
|
||
if (ARGUMENT_PRESENT(lpszNodeName)) {
|
||
lstrcpynW(lpszNodeName, NodeName, *lpcchNodeName);
|
||
Length = lstrlenW(NodeName);
|
||
if (Length >= *lpcchNodeName) {
|
||
Status = ERROR_MORE_DATA;
|
||
State = ClusterResourceStateUnknown;
|
||
}
|
||
*lpcchNodeName = Length;
|
||
}
|
||
if (ARGUMENT_PRESENT(lpszGroupName)) {
|
||
lstrcpynW(lpszGroupName, GroupName, *lpcchGroupName);
|
||
Length = lstrlenW(GroupName);
|
||
if (Length >= *lpcchGroupName) {
|
||
Status = ERROR_MORE_DATA;
|
||
State = ClusterResourceStateUnknown;
|
||
}
|
||
*lpcchGroupName = Length;
|
||
}
|
||
MIDL_user_free(NodeName);
|
||
MIDL_user_free(GroupName);
|
||
} else {
|
||
State = ClusterResourceStateUnknown;
|
||
}
|
||
|
||
SetLastError( Status );
|
||
return( State );
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
SetClusterResourceName(
|
||
IN HRESOURCE hResource,
|
||
IN LPCWSTR lpszResourceName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets the friendly name of a cluster resource
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to a cluster resource
|
||
|
||
lpszResourceName - Supplies the new name of the cluster resource
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
WRAP(Status,
|
||
(ApiSetResourceName(Resource->hResource, lpszResourceName)),
|
||
Resource->Cluster);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
FailClusterResource(
|
||
IN HRESOURCE hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initiates a resource failure. The specified resource is treated as failed.
|
||
This causes the cluster to initiate the same failover process that would
|
||
result if the resource actually failed.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to the resource to be failed over
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
WRAP(Status,
|
||
(ApiFailResource(Resource->hResource)),
|
||
Resource->Cluster);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
OnlineClusterResource(
|
||
IN HRESOURCE hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings an offline resource online.
|
||
|
||
If hDestinationNode is specified, but the resource is not capable
|
||
of being brought online there, this API fails.
|
||
|
||
If NULL is specified as the hDestinationNode, the best possible
|
||
node is chosen by the cluster software.
|
||
|
||
If NULL is specified but no node where this resource
|
||
can be brought online is currently available, this API fails.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to the resource to be failed over
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value. If a suitable
|
||
host node is not availabe, the error value is
|
||
ERROR_HOST_NODE_NOT_AVAILABLE.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
WRAP(Status,
|
||
(ApiOnlineResource(Resource->hResource)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
OfflineClusterResource(
|
||
IN HRESOURCE hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings an online resource offline.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to the resource to be taken offline
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
WRAP(Status,
|
||
(ApiOfflineResource(Resource->hResource)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
DWORD
|
||
WINAPI
|
||
ChangeClusterResourceGroup(
|
||
IN HRESOURCE hResource,
|
||
IN HGROUP hGroup
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Moves a resource from one group to another.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource to be moved. If the resource
|
||
depends on any other resources, those resources will also
|
||
be moved. If other resources depend on the specified resource,
|
||
those resources will also be moved.
|
||
|
||
hGroup - Supplies the group that the resource should be moved into.
|
||
If the resource is online, the specified group must be online
|
||
on the same node.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
DWORD Status;
|
||
PCGROUP Group;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
Group = (PCGROUP)hGroup;
|
||
|
||
WRAP(Status,
|
||
(ApiChangeResourceGroup(Resource->hResource,Group->hGroup)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
DWORD
|
||
WINAPI
|
||
AddClusterResourceNode(
|
||
IN HRESOURCE hResource,
|
||
IN HNODE hNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds a node to the list of possible nodes that the specified
|
||
resource can run on.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose list of potential host
|
||
nodes is to be changed.
|
||
|
||
hNode - Supplies the node which should be added to the resource's list of
|
||
potential host nodes.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource = (PCRESOURCE)hResource;
|
||
PCNODE Node = (PCNODE)hNode;
|
||
DWORD Status;
|
||
|
||
WRAP(Status,
|
||
(ApiAddResourceNode(Resource->hResource, Node->hNode)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
DWORD
|
||
WINAPI
|
||
RemoveClusterResourceNode(
|
||
IN HRESOURCE hResource,
|
||
IN HNODE hNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a node from the list of possible nodes that the specified
|
||
resource can run on.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose list of potential host
|
||
nodes is to be changed.
|
||
|
||
hNode - Supplies the node which should be removed from the resource's
|
||
list of potential host nodes.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource = (PCRESOURCE)hResource;
|
||
PCNODE Node = (PCNODE)hNode;
|
||
DWORD Status;
|
||
|
||
WRAP(Status,
|
||
(ApiRemoveResourceNode(Resource->hResource, Node->hNode)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
DWORD
|
||
WINAPI
|
||
AddClusterResourceDependency(
|
||
IN HRESOURCE hResource,
|
||
IN HRESOURCE hDependsOn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds a dependency relationship between two resources.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the dependent resource.
|
||
|
||
hDependsOn - Supplies the resource that hResource depends on.
|
||
This resource must be in the same group as hResource. If
|
||
hResource is currently online, this resource must also be
|
||
currently online.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
PCRESOURCE DependsOn;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
DependsOn = (PCRESOURCE)hDependsOn;
|
||
|
||
WRAP(Status,
|
||
(ApiAddResourceDependency(Resource->hResource,DependsOn->hResource)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
DWORD
|
||
WINAPI
|
||
RemoveClusterResourceDependency(
|
||
IN HRESOURCE hResource,
|
||
IN HRESOURCE hDependsOn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a dependency relationship between two resources
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the dependent resource
|
||
|
||
hDependsOn - Supplies the resource that hResource is currently
|
||
dependent on.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
PCRESOURCE DependsOn;
|
||
DWORD Status;
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
DependsOn = (PCRESOURCE)hDependsOn;
|
||
|
||
WRAP(Status,
|
||
(ApiRemoveResourceDependency(Resource->hResource,DependsOn->hResource)),
|
||
Resource->Cluster);
|
||
return(Status);
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
CanResourceBeDependent(
|
||
IN HRESOURCE hResource,
|
||
IN HRESOURCE hResourceDependent
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if the resource identified by hResource can depend on hResourceDependent.
|
||
In order for this to be true, both resources must be members of the same group and
|
||
the resource identified by hResourceDependent cannot depend on the resource identified
|
||
by hResource, whether directly or indirectly.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to the resource to be dependent.
|
||
|
||
hResourceDependent - Supplies a handle to the resource on which
|
||
the resource identified by hResource can depend.
|
||
|
||
Return Value:
|
||
|
||
If the resource identified by hResource can depend on the resource
|
||
identified by hResourceDependent, the return value is TRUE. Otherwise,
|
||
the return value is FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
PCRESOURCE Resource1 = (PCRESOURCE)hResource;
|
||
PCRESOURCE Resource2 = (PCRESOURCE)hResourceDependent;
|
||
|
||
WRAP(Status,
|
||
(ApiCanResourceBeDependent(Resource1->hResource,Resource2->hResource)),
|
||
Resource1->Cluster);
|
||
|
||
if (Status == ERROR_SUCCESS) {
|
||
return(TRUE);
|
||
} else {
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
|
||
HRESENUM
|
||
WINAPI
|
||
ClusterResourceOpenEnum(
|
||
IN HRESOURCE hResource,
|
||
IN DWORD dwType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initiates an enumeration of a cluster resource's properties
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies a handle to the resource.
|
||
|
||
dwType - Supplies a bitmask of the type of properties to be
|
||
enumerated. Currently defined types include
|
||
|
||
CLUSTER_RESOURCE_ENUM_DEPENDS - All resources the specified resource
|
||
depends on.
|
||
CLUSTER_RESOURCE_ENUM_PROVIDES - All resources that depend on the
|
||
specified resource.
|
||
CLUSTER_RESOURCE_ENUM_NODES - All nodes that this resource can run
|
||
on.
|
||
|
||
Return Value:
|
||
|
||
If successful, returns a handle suitable for use with ClusterResourceEnum
|
||
|
||
If unsuccessful, returns NULL and GetLastError() returns a more
|
||
specific error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCRESOURCE Resource;
|
||
PENUM_LIST Enum = NULL;
|
||
DWORD Status;
|
||
|
||
if ((dwType & CLUSTER_RESOURCE_ENUM_ALL) == 0) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return(NULL);
|
||
}
|
||
if ((dwType & ~CLUSTER_RESOURCE_ENUM_ALL) != 0) {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return(NULL);
|
||
}
|
||
|
||
Resource = (PCRESOURCE)hResource;
|
||
|
||
WRAP(Status,
|
||
(ApiCreateResEnum(Resource->hResource,
|
||
dwType,
|
||
&Enum)),
|
||
Resource->Cluster);
|
||
if (Status != ERROR_SUCCESS) {
|
||
SetLastError(Status);
|
||
return(NULL);
|
||
}
|
||
return((HRESENUM)Enum);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
ClusterResourceGetEnumCount(
|
||
IN HRESENUM hResEnum
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the number of items contained the the enumerator's collection.
|
||
|
||
Arguments:
|
||
|
||
hEnum - a handle to an enumerator returned by ClusterResourceOpenEnum.
|
||
|
||
Return Value:
|
||
|
||
The number of items (possibly zero) in the enumerator's collection.
|
||
|
||
--*/
|
||
{
|
||
PENUM_LIST Enum = (PENUM_LIST)hResEnum;
|
||
return Enum->EntryCount;
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
ClusterResourceEnum(
|
||
IN HRESENUM hResEnum,
|
||
IN DWORD dwIndex,
|
||
OUT LPDWORD lpdwType,
|
||
OUT LPWSTR lpszName,
|
||
IN OUT LPDWORD lpcchName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the next enumerable resource property.
|
||
|
||
Arguments:
|
||
|
||
hResEnum - Supplies a handle to an open cluster resource enumeration
|
||
returned by ClusterResourceOpenEnum
|
||
|
||
dwIndex - Supplies the index to enumerate. This parameter should be
|
||
zero for the first call to the ClusterResourceEnum function and
|
||
then incremented for subsequent calls.
|
||
|
||
dwType - Returns the type of property.
|
||
|
||
lpszName - Points to a buffer that receives the name of the resource
|
||
property, including the terminating null character.
|
||
|
||
lpcchName - Points to a variable that specifies the size, in characters,
|
||
of the buffer pointed to by the lpszName parameter. This size
|
||
should include the terminating null character. When the function
|
||
returns, the variable pointed to by lpcchName contains the
|
||
number of characters stored in the buffer. The count returned
|
||
does not include the terminating null character.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
DWORD NameLen;
|
||
PENUM_LIST Enum = (PENUM_LIST)hResEnum;
|
||
|
||
if (dwIndex >= Enum->EntryCount) {
|
||
return(ERROR_NO_MORE_ITEMS);
|
||
}
|
||
|
||
NameLen = lstrlenW(Enum->Entry[dwIndex].Name);
|
||
lstrcpynW(lpszName, Enum->Entry[dwIndex].Name, *lpcchName);
|
||
if (*lpcchName < (NameLen + 1)) {
|
||
if (lpszName == NULL) {
|
||
Status = ERROR_SUCCESS;
|
||
} else {
|
||
Status = ERROR_MORE_DATA;
|
||
}
|
||
} else {
|
||
Status = ERROR_SUCCESS;
|
||
}
|
||
|
||
*lpdwType = Enum->Entry[dwIndex].Type;
|
||
*lpcchName = NameLen;
|
||
|
||
return(Status);
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
ClusterResourceCloseEnum(
|
||
IN HRESENUM hResEnum
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Closes an open enumeration for a resource.
|
||
|
||
Arguments:
|
||
|
||
hResEnum - Supplies a handle to the enumeration to be closed.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD i;
|
||
PENUM_LIST Enum = (PENUM_LIST)hResEnum;
|
||
|
||
//
|
||
// Walk through enumeration freeing all the names
|
||
//
|
||
for (i=0; i<Enum->EntryCount; i++) {
|
||
MIDL_user_free(Enum->Entry[i].Name);
|
||
}
|
||
MIDL_user_free(Enum);
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
CreateClusterResourceType(
|
||
IN HCLUSTER hCluster,
|
||
IN LPCWSTR lpszTypeName,
|
||
IN LPCWSTR lpszDisplayName,
|
||
IN LPCWSTR lpszDllName,
|
||
IN DWORD dwLooksAlive,
|
||
IN DWORD dwIsAlive
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a new resource type in the cluster. Note that this API only
|
||
defines the resource type in the cluster registry and registers the
|
||
resource type with the cluster service. The calling program is
|
||
responsible for installing the resource type DLL on each node in the
|
||
cluster.
|
||
|
||
Arguments:
|
||
|
||
hCluster - Supplies a handle to a previously opened cluster.
|
||
|
||
lpszResourceTypeName - Supplies the new resource type<70>s name. The
|
||
specified name must be unique within the cluster.
|
||
|
||
lpszDisplayName - Supplies the display name for the new resource
|
||
type. While lpszResourceTypeName should uniquely identify the
|
||
resource type on all clusters, the lpszDisplayName should be
|
||
a localized friendly name for the resource, suitable for displaying
|
||
to administrators
|
||
|
||
lpszResourceTypeDll - Supplies the name of the new resource type<70>s DLL.
|
||
|
||
dwLooksAlivePollInterval - Supplies the default LooksAlive poll interval
|
||
for the new resource type in milliseconds.
|
||
|
||
dwIsAlivePollInterval - Supplies the default IsAlive poll interval for
|
||
the new resource type in milliseconds.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PCLUSTER Cluster;
|
||
error_status_t Status = ERROR_SUCCESS;
|
||
|
||
Cluster = (PCLUSTER)hCluster;
|
||
|
||
WRAP(Status,
|
||
(ApiCreateResourceType(Cluster->RpcBinding,
|
||
lpszTypeName,
|
||
lpszDisplayName,
|
||
lpszDllName,
|
||
dwLooksAlive,
|
||
dwIsAlive)),
|
||
Cluster);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DeleteClusterResourceType(
|
||
IN HCLUSTER hCluster,
|
||
IN LPCWSTR lpszTypeName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deletes a resource type in the cluster. Note that this API only
|
||
deletes the resource type in the cluster registry and unregisters the
|
||
resource type with the cluster service. The calling program is
|
||
responsible for deleting the resource type DLL on each node in the
|
||
cluster. If any resources of the specified type exist, this API
|
||
fails. The calling program is responsible for deleting any resources
|
||
of this type before deleting the resource type.
|
||
|
||
Arguments:
|
||
|
||
hCluster - Supplies a handle to a previously opened cluster.
|
||
|
||
lpszResourceTypeName - Supplies the name of the resource type to
|
||
be deleted.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PCLUSTER Cluster;
|
||
error_status_t Status = ERROR_SUCCESS;
|
||
|
||
Cluster = (PCLUSTER)hCluster;
|
||
|
||
WRAP(Status,
|
||
(ApiDeleteResourceType(Cluster->RpcBinding,lpszTypeName)),
|
||
Cluster);
|
||
|
||
return(Status);
|
||
|
||
|
||
}
|
||
|
||
/****
|
||
@func HRESTYPEENUM | ClusterResourceTypeOpenEnum | Initiates
|
||
an enumeration of a cluster resource type's properties.
|
||
|
||
@parm IN HCLUSTER | hCluster | Handle to the cluster
|
||
@parm IN LPCWSTR | lpszResourceTypeName | Pointer to the name of the
|
||
resource type
|
||
@parm IN DWORD | dwType | A bitmask of the type of properties
|
||
to be enumerated. Currently, the only defined type is
|
||
CLUSTER_RESOURCE_TYPE_ENUM_NODES.
|
||
@comm This function opens an enumerator for iterating through
|
||
a resource type's nodes
|
||
|
||
@rdesc Returns NULL if the operation is unsuccessful. For
|
||
detailed information about the error, call the Win32
|
||
function GetLastError (). A handle to the enumeration
|
||
on success.
|
||
|
||
@xref <f ClusterResourceTypeEnum> <f ClusterResourceTypeCloseEnum>
|
||
****/
|
||
HRESTYPEENUM
|
||
WINAPI
|
||
ClusterResourceTypeOpenEnum(
|
||
IN HCLUSTER hCluster,
|
||
IN LPCWSTR lpszResourceTypeName,
|
||
IN DWORD dwType
|
||
)
|
||
{
|
||
PCLUSTER pCluster;
|
||
PENUM_LIST Enum = NULL;
|
||
DWORD Status;
|
||
|
||
pCluster = (PCLUSTER)hCluster;
|
||
|
||
if ((dwType & CLUSTER_RESOURCE_TYPE_ENUM_ALL) == 0) {
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto error_exit;
|
||
}
|
||
if ((dwType & ~CLUSTER_RESOURCE_TYPE_ENUM_ALL) != 0) {
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto error_exit;
|
||
}
|
||
|
||
WRAP(Status,
|
||
(ApiCreateResTypeEnum(pCluster->RpcBinding,
|
||
lpszResourceTypeName,
|
||
dwType,
|
||
&Enum)),
|
||
pCluster);
|
||
|
||
if (Status == RPC_S_PROCNUM_OUT_OF_RANGE) {
|
||
//
|
||
// The current node is NT4Sp4 or lower. Try
|
||
// some other node in the cluster
|
||
//
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnum - Current Cluster Node is NTSp4 or lower !!!\n"));
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnum - Trying some other candidate ...\n"));
|
||
Enum = (PENUM_LIST)ClusterResourceTypeOpenEnumFromCandidate(hCluster,
|
||
lpszResourceTypeName,
|
||
dwType);
|
||
if (Enum == NULL)
|
||
{
|
||
//
|
||
// Did not find a node NT4Sp5 or higher AND at least
|
||
// one node is down. Can't enumerate.
|
||
//
|
||
TIME_PRINT(("ClusterResourceTypeOpenEnum - ClusterResourceTypeOpenEnumFromCandidate failed !!!\n"));
|
||
Status = GetLastError ();
|
||
goto error_exit;
|
||
}
|
||
Status = ERROR_SUCCESS;
|
||
}
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
return((HRESTYPEENUM)Enum);
|
||
|
||
error_exit:
|
||
SetLastError(Status);
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
ClusterResourceTypeGetEnumCount(
|
||
IN HRESTYPEENUM hResTypeEnum
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the number of items contained the the enumerator's collection.
|
||
|
||
Arguments:
|
||
|
||
hEnum - a handle to an enumerator returned by ClusterResourceTypeOpenEnum.
|
||
|
||
Return Value:
|
||
|
||
The number of items (possibly zero) in the enumerator's collection.
|
||
|
||
--*/
|
||
{
|
||
PENUM_LIST Enum = (PENUM_LIST)hResTypeEnum;
|
||
return Enum->EntryCount;
|
||
}
|
||
|
||
|
||
/****
|
||
@func DWORD | ClusterResourceTypeEnum | Enumerates a resource
|
||
type's nodes, returning the name of one object per call.
|
||
|
||
@parm IN HRESTYPEENUM | hResTypeEnum | Supplies a handle to
|
||
an open cluster resource enumeration returned by
|
||
ClusterResourceTypeOpenEnum.
|
||
@parm IN DWORD | dwIndex | Supplies the index to enumerate.
|
||
This parameter should be zero for the first call
|
||
to the ClusterResourceTypeEnum function and
|
||
then incremented for subsequent calls.
|
||
@parm OUT DWORD | lpdwType | Returns the type of property.
|
||
Currently, the only defined type is
|
||
CLUSTER_RESOURCE_TYPE_ENUM_NODES.
|
||
@parm OUT LPWSTR | lpszName | Points to a buffer that
|
||
receives the name of the resource type.
|
||
@parm IN OUT LPDWORD | lpcchName | Points to a variable that
|
||
specifies the size, in characters, of the buffer
|
||
pointed to by the lpszName parameter. This size
|
||
should include the terminating null character.
|
||
When the function returns, the variable pointed
|
||
to by lpcchName contains the number of characters
|
||
stored in the buffer. The count returned
|
||
does not include the terminating null character.
|
||
property, including the terminating null character.
|
||
@comm This function opens an enumerator for iterating through
|
||
a resource type's nodes.
|
||
|
||
@rdesc Returns a Win32 error code if the operation is
|
||
unsuccessful. ERROR_SUCCESS on success.
|
||
|
||
@xref <f ClusterResourceTypeOpenEnum> <f ClusterResourceTypeCloseEnum>
|
||
****/
|
||
DWORD
|
||
WINAPI
|
||
ClusterResourceTypeEnum(
|
||
IN HRESTYPEENUM hResTypeEnum,
|
||
IN DWORD dwIndex,
|
||
OUT LPDWORD lpdwType,
|
||
OUT LPWSTR lpszName,
|
||
IN OUT LPDWORD lpcchName
|
||
)
|
||
{
|
||
DWORD Status;
|
||
DWORD NameLen;
|
||
PENUM_LIST Enum = (PENUM_LIST)hResTypeEnum;
|
||
|
||
if ((Enum == NULL) ||
|
||
(lpcchName == NULL) ||
|
||
(lpdwType == NULL)) {
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto error_exit;
|
||
}
|
||
if (dwIndex >= Enum->EntryCount) {
|
||
Status = ERROR_NO_MORE_ITEMS;
|
||
goto error_exit;
|
||
}
|
||
|
||
NameLen = lstrlenW(Enum->Entry[dwIndex].Name);
|
||
lstrcpynW(lpszName, Enum->Entry[dwIndex].Name, *lpcchName);
|
||
if (*lpcchName < (NameLen + 1)) {
|
||
if (lpszName == NULL) {
|
||
Status = ERROR_SUCCESS;
|
||
} else {
|
||
Status = ERROR_MORE_DATA;
|
||
}
|
||
} else {
|
||
Status = ERROR_SUCCESS;
|
||
}
|
||
|
||
*lpdwType = Enum->Entry[dwIndex].Type;
|
||
*lpcchName = NameLen;
|
||
|
||
error_exit:
|
||
return(Status);
|
||
}
|
||
|
||
/****
|
||
@func DWORD | ClusterResourceTypeCloseEnum | Closes an open
|
||
enumeration for a resource type.
|
||
|
||
@parm IN HRESTYPEENUM | hResTypeEnum | Handle to the
|
||
enumeration to be closed.
|
||
@comm This function closes an open enumeration.
|
||
|
||
@rdesc Returns ERROR_SUCCESS on success. A Win32 error code otherwise.
|
||
|
||
@xref <f ClusterResourceTypeEnum> <f ClusterResourceTypeOpenEnum>
|
||
****/
|
||
DWORD
|
||
WINAPI
|
||
ClusterResourceTypeCloseEnum(
|
||
IN HRESTYPEENUM hResTypeEnum
|
||
)
|
||
{
|
||
DWORD i;
|
||
PENUM_LIST Enum = (PENUM_LIST)hResTypeEnum;
|
||
DWORD Status;
|
||
|
||
if (Enum == NULL) {
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Walk through enumeration freeing all the names
|
||
//
|
||
for (i=0; i<Enum->EntryCount; i++) {
|
||
MIDL_user_free(Enum->Entry[i].Name);
|
||
}
|
||
MIDL_user_free(Enum);
|
||
Status = ERROR_SUCCESS;
|
||
|
||
error_exit:
|
||
return(Status);
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
GetClusterResourceNetworkName(
|
||
IN HRESOURCE hResource,
|
||
OUT LPWSTR lpBuffer,
|
||
IN OUT LPDWORD nSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enumerates the dependencies of a resource in an attempt to find
|
||
a network name that the resource depends on. If a network name
|
||
is found, this function returns TRUE and fills in lpBuffer with
|
||
the network name. If a network name is not found, this function
|
||
returns FALSE.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource.
|
||
|
||
lpBuffer - Points to a buffer to receive the null-terminated character
|
||
string containing the network name.
|
||
|
||
nSize - Points to a variable that specifies the maximum size, in characters,
|
||
of the buffer. This value should be large enough to contain
|
||
MAX_COMPUTERNAME_LENGTH + 1 characters.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful
|
||
|
||
FALSE if unsuccessful
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL Success;
|
||
PCRESOURCE Resource = (PCRESOURCE)hResource;
|
||
|
||
//
|
||
// Call a recursive worker to do the search.
|
||
//
|
||
Success = FindNetworkWorker(Resource->hResource,
|
||
Resource->Cluster,
|
||
lpBuffer,
|
||
nSize);
|
||
return(Success);
|
||
}
|
||
|
||
|
||
BOOL
|
||
FindNetworkWorker(
|
||
IN HRES_RPC hResource,
|
||
IN PCLUSTER Cluster,
|
||
OUT LPWSTR lpBuffer,
|
||
IN OUT LPDWORD nSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Recursive worker to search a resource's dependency tree
|
||
for a network name resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - Supplies the resource.
|
||
|
||
Cluster - Supplies the cluster.
|
||
|
||
lpBuffer - Points to a buffer to receive the null-terminated character
|
||
string containing the network name.
|
||
|
||
nSize - Points to a variable that specifies the maximum size, in characters,
|
||
of the buffer. This value should be large enough to contain
|
||
MAX_COMPUTERNAME_LENGTH + 1 characters.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful
|
||
|
||
FALSE if unsuccessful
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL Success = FALSE;
|
||
DWORD i;
|
||
PENUM_LIST Enum=NULL;
|
||
DWORD Status;
|
||
HRES_RPC hRes;
|
||
LPWSTR TypeName;
|
||
|
||
|
||
//
|
||
// Create a dependency enumeration
|
||
//
|
||
WRAP(Status,
|
||
(ApiCreateResEnum(hResource,
|
||
CLUSTER_RESOURCE_ENUM_DEPENDS,
|
||
&Enum)),
|
||
Cluster);
|
||
if (Status != ERROR_SUCCESS) {
|
||
SetLastError(Status);
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Open each resource in the dependency and see if it is a network name
|
||
// resource.
|
||
//
|
||
for (i=0; i<Enum->EntryCount; i++) {
|
||
WRAP_NULL(hRes,
|
||
(ApiOpenResource(Cluster->RpcBinding,
|
||
Enum->Entry[i].Name,
|
||
&Status)),
|
||
&Status,
|
||
Cluster);
|
||
if (hRes != NULL) {
|
||
TypeName = NULL;
|
||
WRAP(Status,
|
||
(ApiGetResourceType(hRes,
|
||
&TypeName)),
|
||
Cluster);
|
||
if (Status == ERROR_SUCCESS) {
|
||
//
|
||
// See if this type name matches.
|
||
//
|
||
if (lstrcmpiW(TypeName, CLUS_RESTYPE_NAME_NETNAME) == 0) {
|
||
HRESOURCE NetResource;
|
||
HKEY NetKey;
|
||
HKEY NetParamKey;
|
||
//
|
||
// We have a match, pull out the Name parameter.
|
||
// Go ahead and really open the resource so we
|
||
// can use the registry functions on it.
|
||
//
|
||
NetResource = OpenClusterResource((HCLUSTER)Cluster,
|
||
Enum->Entry[i].Name);
|
||
if (NetResource != NULL) {
|
||
NetKey = GetClusterResourceKey(NetResource, KEY_READ);
|
||
CloseClusterResource(NetResource);
|
||
if (NetKey != NULL) {
|
||
Status = ClusterRegOpenKey(NetKey,
|
||
CLUSREG_KEYNAME_PARAMETERS,
|
||
KEY_READ,
|
||
&NetParamKey);
|
||
ClusterRegCloseKey(NetKey);
|
||
if (Status == ERROR_SUCCESS) {
|
||
DWORD cbData;
|
||
|
||
|
||
cbData = *nSize * sizeof(WCHAR);
|
||
Status = ClusterRegQueryValue(NetParamKey,
|
||
CLUSREG_NAME_RES_NAME,
|
||
NULL,
|
||
(LPBYTE)lpBuffer,
|
||
&cbData);
|
||
ClusterRegCloseKey(NetParamKey);
|
||
if (Status == ERROR_SUCCESS) {
|
||
Success = TRUE;
|
||
*nSize = wcslen(lpBuffer);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Try the dependents of this resource
|
||
//
|
||
Success = FindNetworkWorker(hRes,
|
||
Cluster,
|
||
lpBuffer,
|
||
nSize);
|
||
}
|
||
MIDL_user_free(TypeName);
|
||
}
|
||
|
||
ApiCloseResource(&hRes);
|
||
if (Success) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!Success && (Status == ERROR_SUCCESS)) {
|
||
Status = ERROR_DEPENDENCY_NOT_FOUND;
|
||
}
|
||
if (Status != ERROR_SUCCESS) {
|
||
SetLastError(Status);
|
||
}
|
||
|
||
MIDL_user_free(Enum);
|
||
return(Success);
|
||
}
|
||
|
||
|
||
HCLUSTER
|
||
WINAPI
|
||
GetClusterFromResource(
|
||
IN HRESOURCE hResource
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the cluster handle from the associated resource handle.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource.
|
||
|
||
Return Value:
|
||
|
||
Handle to the cluster associated with the resource handle.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD nStatus;
|
||
PCRESOURCE Resource = (PCRESOURCE)hResource;
|
||
HCLUSTER hCluster = (HCLUSTER)Resource->Cluster;
|
||
|
||
nStatus = AddRefToClusterHandle( hCluster );
|
||
if ( nStatus != ERROR_SUCCESS ) {
|
||
SetLastError( nStatus );
|
||
hCluster = NULL;
|
||
}
|
||
return( hCluster );
|
||
|
||
} // GetClusterFromResource()
|