1718 lines
41 KiB
C
1718 lines
41 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
resource.c
|
||
|
||
Abstract:
|
||
|
||
Server side support for Cluster APIs dealing with resources
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 7-Mar-1996
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "apip.h"
|
||
|
||
HRES_RPC
|
||
s_ApiOpenResource(
|
||
IN handle_t IDL_handle,
|
||
IN LPCWSTR lpszResourceName,
|
||
OUT error_status_t *Status
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens a handle to an existing resource object.
|
||
|
||
Arguments:
|
||
|
||
IDL_handle - RPC binding handle, not used.
|
||
|
||
lpszResourceName - Supplies the name of the resource to open.
|
||
|
||
Status - Returns any error that may occur.
|
||
|
||
Return Value:
|
||
|
||
A context handle to a resource object if successful
|
||
|
||
NULL otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRES_RPC Resource;
|
||
PAPI_HANDLE Handle;
|
||
|
||
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
|
||
if (Handle == NULL) {
|
||
*Status = ERROR_NOT_ENOUGH_MEMORY;
|
||
return(NULL);
|
||
}
|
||
Resource = OmReferenceObjectByName(ObjectTypeResource, lpszResourceName);
|
||
if (Resource == NULL) {
|
||
LocalFree(Handle);
|
||
*Status = ERROR_RESOURCE_NOT_FOUND;
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[API] s_ApiOpenResource: Resource %1!ws! not found, status = %2!u!...\n",
|
||
lpszResourceName,
|
||
*Status);
|
||
return(NULL);
|
||
}
|
||
*Status = ERROR_SUCCESS;
|
||
Handle->Type = API_RESOURCE_HANDLE;
|
||
Handle->Resource = Resource;
|
||
Handle->Flags = 0;
|
||
InitializeListHead(&Handle->NotifyList);
|
||
return(Handle);
|
||
}
|
||
|
||
HRES_RPC
|
||
s_ApiCreateResource(
|
||
IN HGROUP_RPC hGroup,
|
||
IN LPCWSTR lpszResourceName,
|
||
IN LPCWSTR lpszResourceType,
|
||
IN DWORD dwFlags,
|
||
OUT error_status_t *pStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a new resource object.
|
||
|
||
Arguments:
|
||
|
||
hGroup - Supplies the group the resource is to be created in.
|
||
|
||
lpszResourceName - Supplies the name of the resource to create.
|
||
|
||
lpszResourceType - Supplies the type of the resource.
|
||
|
||
dwFlags - Supplies any optional flags.
|
||
|
||
Status - Returns any error that may occur.
|
||
|
||
Return Value:
|
||
|
||
A context handle to a resource object if successful
|
||
|
||
NULL otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
HRES_RPC Resource=NULL;
|
||
PFM_GROUP Group;
|
||
UUID Guid;
|
||
DWORD Status = ERROR_SUCCESS;
|
||
WCHAR *KeyName=NULL;
|
||
HDMKEY Key=NULL;
|
||
HDMKEY GroupKey=NULL;
|
||
HDMKEY TypeKey = NULL;
|
||
HDMKEY ParamKey;
|
||
DWORD Disposition;
|
||
DWORD pollIntervals = CLUSTER_RESOURCE_USE_DEFAULT_POLL_INTERVAL;
|
||
PAPI_HANDLE Handle;
|
||
PFM_RESTYPE ResType;
|
||
DWORD dwPersistentState = 0;
|
||
DWORD dwClusterHighestVersion;
|
||
|
||
if (ApiState != ApiStateOnline)
|
||
{
|
||
*pStatus = ERROR_SHARING_PAUSED;
|
||
return(NULL);
|
||
}
|
||
|
||
if (((PAPI_HANDLE)hGroup)->Type != API_GROUP_HANDLE)
|
||
{
|
||
*pStatus = ERROR_INVALID_HANDLE;
|
||
return(NULL);
|
||
}
|
||
Group = ((PAPI_HANDLE)hGroup)->Group;
|
||
|
||
|
||
//
|
||
// Check for bogus flags.
|
||
//
|
||
if (dwFlags & ~CLUSTER_RESOURCE_VALID_FLAGS)
|
||
{
|
||
*pStatus = ERROR_INVALID_PARAMETER;
|
||
return(NULL);
|
||
}
|
||
|
||
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
|
||
if (Handle == NULL)
|
||
{
|
||
*pStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Chittur Subbaraman (chitturs) - 1/30/2000
|
||
//
|
||
// If we are dealing with the mixed mode cluster, do the
|
||
// registry updates right here since the GUM handler won't do it.
|
||
//
|
||
NmGetClusterOperationalVersion( &dwClusterHighestVersion,
|
||
NULL,
|
||
NULL );
|
||
|
||
//
|
||
// Open the resource type key. This validates that the specified type exists.
|
||
//
|
||
TypeKey = DmOpenKey(DmResourceTypesKey,
|
||
lpszResourceType,
|
||
KEY_READ);
|
||
if (TypeKey == NULL)
|
||
{
|
||
Status = GetLastError();
|
||
goto error_exit;
|
||
}
|
||
|
||
retry:
|
||
//
|
||
// Create a GUID for this resource.
|
||
//
|
||
Status = UuidCreate(&Guid);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
Status = UuidToString(&Guid, &KeyName);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[API] Creating resource %1!ws! <%2!ws!> (%3!ws!)\n",
|
||
lpszResourceType,
|
||
lpszResourceName,
|
||
KeyName);
|
||
|
||
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
|
||
NT51_MAJOR_VERSION )
|
||
{
|
||
//
|
||
// Create the new resource key.
|
||
//
|
||
Key = DmCreateKey(DmResourcesKey,
|
||
KeyName,
|
||
0,
|
||
KEY_READ | KEY_WRITE,
|
||
NULL,
|
||
&Disposition);
|
||
if (Key == NULL)
|
||
{
|
||
Status = GetLastError();
|
||
goto error_exit;
|
||
}
|
||
if (Disposition != REG_CREATED_NEW_KEY)
|
||
{
|
||
ClRtlLogPrint(LOG_CRITICAL,
|
||
"[API] ApiCreateResource generated GUID %1!ws! that already existed! This is impossible.\n",
|
||
KeyName);
|
||
DmCloseKey(Key);
|
||
RpcStringFree(&KeyName);
|
||
goto retry;
|
||
}
|
||
|
||
CL_ASSERT(Disposition == REG_CREATED_NEW_KEY);
|
||
|
||
//
|
||
// Set the resource's name in the registry
|
||
//
|
||
Status = DmSetValue(Key,
|
||
CLUSREG_NAME_RES_NAME,
|
||
REG_SZ,
|
||
(CONST BYTE *)lpszResourceName,
|
||
(lstrlenW(lpszResourceName)+1)*sizeof(WCHAR));
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Set the resource's type in the registry
|
||
// Note we reference the resource type and use its ID
|
||
// so that the case is correct.
|
||
//
|
||
ResType = OmReferenceObjectById(ObjectTypeResType, lpszResourceType);
|
||
CL_ASSERT(ResType != NULL);
|
||
lpszResourceType = OmObjectId(ResType);
|
||
OmDereferenceObject(ResType);
|
||
Status = DmSetValue(Key,
|
||
CLUSREG_NAME_RES_TYPE,
|
||
REG_SZ,
|
||
(CONST BYTE *)lpszResourceType,
|
||
(lstrlenW(lpszResourceType)+1)*sizeof(WCHAR));
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Set the resource's poll intervals in the registry.
|
||
//
|
||
Status = DmSetValue(Key,
|
||
CLUSREG_NAME_RES_LOOKS_ALIVE,
|
||
REG_DWORD,
|
||
(CONST BYTE *)&pollIntervals,
|
||
4);
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
Status = DmSetValue(Key,
|
||
CLUSREG_NAME_RES_IS_ALIVE,
|
||
REG_DWORD,
|
||
(CONST BYTE *)&pollIntervals,
|
||
4);
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// If this resource should be started in a separate monitor, set that
|
||
// parameter now.
|
||
//
|
||
if (dwFlags & CLUSTER_RESOURCE_SEPARATE_MONITOR)
|
||
{
|
||
DWORD SeparateMonitor = 1;
|
||
|
||
Status = DmSetValue(Key,
|
||
CLUSREG_NAME_RES_SEPARATE_MONITOR,
|
||
REG_DWORD,
|
||
(CONST BYTE *)&SeparateMonitor,
|
||
sizeof(SeparateMonitor));
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Create a Parameters key for the resource.
|
||
//
|
||
ParamKey = DmCreateKey(Key,
|
||
CLUSREG_KEYNAME_PARAMETERS,
|
||
0,
|
||
KEY_READ,
|
||
NULL,
|
||
&Disposition);
|
||
if (ParamKey == NULL)
|
||
{
|
||
CL_LOGFAILURE(GetLastError());
|
||
} else
|
||
{
|
||
DmCloseKey(ParamKey);
|
||
}
|
||
|
||
GroupKey = DmOpenKey(DmGroupsKey, OmObjectId(Group), KEY_READ | KEY_WRITE);
|
||
if (GroupKey == NULL)
|
||
{
|
||
Status = GetLastError();
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// Chittur Subbaraman (chitturs) - 5/25/99
|
||
//
|
||
// Make sure you set the persistent state of the resource to
|
||
// ClusterResourceOffline before you create the resource. If
|
||
// this is not done, if you create a resource in a group which
|
||
// is online, the group's persistent state value (i.e., 1 in
|
||
// this case) is inherited by the resource in FmpQueryResourceInfo
|
||
// (only the memory state is set and not the registry state and
|
||
// this was a problem as well) and if you move such a group to
|
||
// another node, it will bring the newly created resource online.
|
||
//
|
||
Status = DmSetValue( Key,
|
||
CLUSREG_NAME_RES_PERSISTENT_STATE,
|
||
REG_DWORD,
|
||
( CONST BYTE * )&dwPersistentState,
|
||
sizeof( DWORD ) );
|
||
|
||
if ( Status != ERROR_SUCCESS )
|
||
{
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
Resource = FmCreateResource(Group, KeyName, lpszResourceName, lpszResourceType, dwFlags);
|
||
|
||
if (Resource == NULL)
|
||
{
|
||
Status = GetLastError();
|
||
if (Status == ERROR_ALREADY_EXISTS)
|
||
{
|
||
RpcStringFree(&KeyName);
|
||
goto retry;
|
||
}
|
||
goto error_exit;
|
||
}
|
||
|
||
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
|
||
NT51_MAJOR_VERSION )
|
||
{
|
||
//
|
||
// Add the resource to the Contains value of the specified group.
|
||
//
|
||
Status = DmAppendToMultiSz(GroupKey,
|
||
CLUSREG_NAME_GRP_CONTAINS,
|
||
KeyName);
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
//
|
||
// BUGBUG John Vert (jvert) 3-May-1996
|
||
// Need to delete this from the FM!
|
||
//
|
||
OmDereferenceObject(Resource);
|
||
Resource = NULL;
|
||
}
|
||
}
|
||
|
||
error_exit:
|
||
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
|
||
NT51_MAJOR_VERSION )
|
||
{
|
||
if (Key != NULL)
|
||
{
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
//
|
||
// Try and cleanup the key we just created.
|
||
//
|
||
DmDeleteKey(Key, CLUSREG_KEYNAME_PARAMETERS);
|
||
DmDeleteKey(DmResourcesKey, KeyName);
|
||
}
|
||
DmCloseKey(Key);
|
||
}
|
||
if (GroupKey != NULL)
|
||
{
|
||
DmCloseKey(GroupKey);
|
||
}
|
||
}
|
||
|
||
if (TypeKey != NULL)
|
||
{
|
||
DmCloseKey(TypeKey);
|
||
}
|
||
|
||
if (KeyName != NULL)
|
||
{
|
||
RpcStringFree(&KeyName);
|
||
}
|
||
|
||
*pStatus = Status;
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
LocalFree(Handle);
|
||
return(NULL);
|
||
}
|
||
|
||
CL_ASSERT(Resource != NULL);
|
||
Handle->Type = API_RESOURCE_HANDLE;
|
||
Handle->Resource = Resource;
|
||
Handle->Flags = 0;
|
||
InitializeListHead(&Handle->NotifyList);
|
||
return(Handle);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiDeleteResource(
|
||
IN HRES_RPC hResource
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deletes the specified cluster resource from the group. The resource
|
||
must have no other resources dependent on it.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the cluster resource to be deleted.
|
||
|
||
Return Value:
|
||
|
||
If the function succeeds, the return value is ERROR_SUCCESS.
|
||
|
||
If the function fails, the return value is an error value.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
DWORD Status;
|
||
HDMKEY Key;
|
||
HDMKEY GroupKey;
|
||
DWORD dwClusterHighestVersion;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
//
|
||
// Chittur Subbaraman (chitturs) - 09/07/2000
|
||
//
|
||
// If we are dealing with a Whistler-Win2K cluster, do the
|
||
// registry updates right here since the GUM handler won't do it.
|
||
//
|
||
NmGetClusterOperationalVersion( &dwClusterHighestVersion,
|
||
NULL,
|
||
NULL );
|
||
|
||
Status = FmDeleteResource(Resource);
|
||
|
||
if ( ( Status == ERROR_SUCCESS ) &&
|
||
( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
|
||
NT51_MAJOR_VERSION ) ) {
|
||
Status = DmDeleteTree(DmResourcesKey,OmObjectId(Resource));
|
||
if ( (Status != ERROR_SUCCESS) &&
|
||
(Status != ERROR_FILE_NOT_FOUND) ) {
|
||
CL_LOGFAILURE( Status );
|
||
return(Status);
|
||
}
|
||
GroupKey = DmOpenKey(DmGroupsKey,
|
||
OmObjectId(Resource->Group),
|
||
KEY_READ | KEY_SET_VALUE);
|
||
if (GroupKey != NULL) {
|
||
DmRemoveFromMultiSz(GroupKey,
|
||
CLUSREG_NAME_GRP_CONTAINS,
|
||
OmObjectId(Resource));
|
||
DmCloseKey(GroupKey);
|
||
}
|
||
}
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiCloseResource(
|
||
IN OUT HRES_RPC *phResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Closes an open resource context handle.
|
||
|
||
Arguments:
|
||
|
||
Resource - Supplies a pointer to the HRES_RPC to be closed.
|
||
Returns NULL
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PAPI_HANDLE Handle;
|
||
|
||
VALIDATE_RESOURCE(Resource, *phResource);
|
||
|
||
Handle = (PAPI_HANDLE)*phResource;
|
||
ApipRundownNotify(Handle);
|
||
OmDereferenceObject(Resource);
|
||
|
||
LocalFree(*phResource);
|
||
*phResource = NULL;
|
||
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
VOID
|
||
HRES_RPC_rundown(
|
||
IN HRES_RPC Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
RPC rundown procedure for a HRES_RPC. Just closes the handle.
|
||
|
||
Arguments:
|
||
|
||
Resource - Supplies the HRES_RPC that is to be rundown.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
s_ApiCloseResource(&Resource);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiGetResourceState(
|
||
IN HRES_RPC hResource,
|
||
OUT DWORD *lpState,
|
||
OUT LPWSTR *lpNodeId,
|
||
OUT LPWSTR *lpGroupName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the current state of the specified resource.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose state is to be returned.
|
||
|
||
lpState - Returns the current state of the resource
|
||
|
||
lpNodeId - Returns the Id of the node where the resource is currently online
|
||
|
||
lpGroupName - Returns the name of the group the the resource is a member of
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
LPWSTR NodeId;
|
||
DWORD IdLength;
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
IdLength = MAX_COMPUTERNAME_LENGTH+1;
|
||
NodeId = MIDL_user_allocate(IdLength*sizeof(WCHAR));
|
||
if (NodeId == NULL) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
*lpState = FmGetResourceState( Resource,
|
||
NodeId,
|
||
&IdLength);
|
||
if ( *lpState == ClusterResourceStateUnknown ) {
|
||
MIDL_user_free(NodeId);
|
||
return(GetLastError());
|
||
}
|
||
*lpNodeId = NodeId;
|
||
*lpGroupName = ApipGetObjectName(Resource->Group);
|
||
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiSetResourceName(
|
||
IN HRES_RPC hResource,
|
||
IN LPCWSTR lpszResourceName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets the new friendly name of a resource.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose name is to be set.
|
||
|
||
lpszResourceName - Supplies the new name of hResource
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
DWORD Status;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
//
|
||
// Tell the FM about the new name. If it is OK with the
|
||
// FM, go ahead and update the registry.
|
||
//
|
||
Status = FmSetResourceName(Resource,
|
||
lpszResourceName);
|
||
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
error_status_t
|
||
s_ApiGetResourceId(
|
||
IN HRES_RPC hResource,
|
||
OUT LPWSTR *pGuid
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the unique identifier (GUID) for a resource.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose identifer is to be returned
|
||
|
||
pGuid - Returns the unique identifier. This memory must be freed on the
|
||
client side.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
DWORD NameLen;
|
||
LPCWSTR Name;
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
Name = OmObjectId(Resource);
|
||
|
||
NameLen = (lstrlenW(Name)+1)*sizeof(WCHAR);
|
||
*pGuid = MIDL_user_allocate(NameLen);
|
||
if (*pGuid == NULL) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
CopyMemory(*pGuid, Name, NameLen);
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiGetResourceType(
|
||
IN HRES_RPC hResource,
|
||
OUT LPWSTR *lpszResourceType
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the resource type for a resource.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose identifer is to be returned
|
||
|
||
lpszResourceType - Returns the resource type name. This memory must be
|
||
freed on the client side.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
DWORD NameLen;
|
||
LPCWSTR Name;
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
if ( Resource->Type == NULL ) {
|
||
return(ERROR_INVALID_STATE);
|
||
}
|
||
|
||
Name = OmObjectId(Resource->Type);
|
||
|
||
NameLen = (lstrlenW(Name)+1)*sizeof(WCHAR);
|
||
*lpszResourceType = MIDL_user_allocate(NameLen);
|
||
if (*lpszResourceType == NULL) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
CopyMemory(*lpszResourceType, Name, NameLen);
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
DWORD
|
||
s_ApiOnlineResource(
|
||
IN HRES_RPC hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings a resource and all its dependencies online
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource to be brought online
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE(Resource, hResource);
|
||
|
||
return(FmOnlineResource(Resource));
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
s_ApiFailResource(
|
||
IN HRES_RPC 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 the resource to be failed over
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
return(FmFailResource(Resource));
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
s_ApiOfflineResource(
|
||
IN HRES_RPC hResource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings a resource and all its dependents offline
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource to be brought offline
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
return(FmOfflineResource(Resource));
|
||
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiAddResourceDependency(
|
||
IN HRES_RPC hResource,
|
||
IN HRES_RPC hDependsOn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds a dependency relationship to a given resource. Both
|
||
resources must be in the same group.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource which is dependent.
|
||
|
||
hDependsOn - Supplies the resource that hResource depends on.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
Win32 error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PFM_RESOURCE DependsOn;
|
||
DWORD Status;
|
||
HDMKEY ResKey;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
VALIDATE_RESOURCE_EXISTS(DependsOn, hDependsOn);
|
||
|
||
//
|
||
// Call the FM to create the dependency relationship.
|
||
//
|
||
Status = FmAddResourceDependency(Resource, DependsOn);
|
||
if (Status == ERROR_SUCCESS) {
|
||
//
|
||
// Add the dependency information to the cluster database.
|
||
//
|
||
ResKey = DmOpenKey(DmResourcesKey,
|
||
OmObjectId(Resource),
|
||
KEY_READ | KEY_SET_VALUE);
|
||
if (ResKey == NULL) {
|
||
Status = GetLastError();
|
||
CL_LOGFAILURE(Status);
|
||
} else {
|
||
Status = DmAppendToMultiSz(ResKey,
|
||
CLUSREG_NAME_RES_DEPENDS_ON,
|
||
OmObjectId(DependsOn));
|
||
DmCloseKey(ResKey);
|
||
}
|
||
if (Status != ERROR_SUCCESS) {
|
||
FmRemoveResourceDependency(Resource, DependsOn);
|
||
}
|
||
}
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiRemoveResourceDependency(
|
||
IN HRES_RPC hResource,
|
||
IN HRES_RPC hDependsOn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a dependency relationship to a given resource. Both
|
||
resources must be in the same group.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource which is dependent.
|
||
|
||
hDependsOn - Supplies the resource that hResource depends on.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
Win32 error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PFM_RESOURCE DependsOn;
|
||
DWORD Status;
|
||
HDMKEY ResKey;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
VALIDATE_RESOURCE_EXISTS(DependsOn, hDependsOn);
|
||
|
||
//
|
||
// If the resources are not in the same group, fail the
|
||
// call. Also fail if some one tries to make a resource
|
||
// dependent upon itself.
|
||
//
|
||
if ((Resource->Group != DependsOn->Group) ||
|
||
(Resource == DependsOn)) {
|
||
return(ERROR_DEPENDENCY_NOT_FOUND);
|
||
}
|
||
|
||
//
|
||
// Remove the dependency from the registry database.
|
||
//
|
||
ResKey = DmOpenKey(DmResourcesKey,
|
||
OmObjectId(Resource),
|
||
KEY_READ | KEY_SET_VALUE);
|
||
if (ResKey == NULL) {
|
||
Status = GetLastError();
|
||
CL_LOGFAILURE(Status);
|
||
} else {
|
||
Status = DmRemoveFromMultiSz(ResKey,
|
||
CLUSREG_NAME_RES_DEPENDS_ON,
|
||
OmObjectId(DependsOn));
|
||
DmCloseKey(ResKey);
|
||
}
|
||
|
||
if (Status == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Call the FM to remove the dependency relationship.
|
||
//
|
||
Status = FmRemoveResourceDependency(Resource, DependsOn);
|
||
|
||
} else if (Status == ERROR_FILE_NOT_FOUND) {
|
||
|
||
//
|
||
// Map this expected error to something a little more reasonable.
|
||
//
|
||
Status = ERROR_DEPENDENCY_NOT_FOUND;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiCanResourceBeDependent(
|
||
IN HRES_RPC hResource,
|
||
IN HRES_RPC 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 ERROR_SUCCESS.
|
||
|
||
Otherwise, the return value is ERROR_DEPENDENCY_ALREADY_EXISTS.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PFM_RESOURCE ResourceDependent;
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
VALIDATE_RESOURCE_EXISTS(ResourceDependent, hResourceDependent);
|
||
|
||
if (Resource == ResourceDependent) {
|
||
//
|
||
// The caller is confused and is trying to make something
|
||
// depend on itself.
|
||
//
|
||
return(ERROR_DEPENDENCY_ALREADY_EXISTS);
|
||
}
|
||
|
||
if (Resource->Group != ResourceDependent->Group) {
|
||
//
|
||
// The caller is confused and is trying to make something
|
||
// depend on a resource in another group.
|
||
//
|
||
return(ERROR_DEPENDENCY_ALREADY_EXISTS);
|
||
}
|
||
|
||
if (FmDependentResource(ResourceDependent, Resource, FALSE)) {
|
||
return(ERROR_DEPENDENCY_ALREADY_EXISTS);
|
||
} else {
|
||
|
||
//
|
||
// Finally check to make sure an immediate dependency does
|
||
// not already exist.
|
||
//
|
||
if (FmDependentResource(Resource, ResourceDependent, TRUE)) {
|
||
return(ERROR_DEPENDENCY_ALREADY_EXISTS);
|
||
} else {
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiCreateResEnum(
|
||
IN HRES_RPC hResource,
|
||
IN DWORD dwType,
|
||
OUT PENUM_LIST *ReturnEnum
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enumerates all the specified resource properties and returns the
|
||
list of objects to the caller. The client-side is responsible
|
||
for freeing the allocated memory.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose properties are to be
|
||
enumerated.
|
||
|
||
dwType - Supplies the type of properties to be enumerated.
|
||
|
||
ReturnEnum - Returns the requested objects.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
DWORD Allocated = 0;
|
||
PENUM_LIST Enum = NULL;
|
||
PENUM_LIST NewEnum = NULL;
|
||
DWORD i;
|
||
DWORD Result;
|
||
PFM_RESOURCE Resource;
|
||
PFM_RESOURCE Target;
|
||
PNM_NODE Node;
|
||
LPWSTR RealName;
|
||
|
||
if (dwType & ~CLUSTER_RESOURCE_ENUM_ALL) {
|
||
return(ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
Allocated = INITIAL_ENUM_LIST_ALLOCATION;
|
||
Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));
|
||
if (Enum == NULL) {
|
||
Status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ErrorExit;
|
||
}
|
||
Enum->EntryCount = 0;
|
||
|
||
//
|
||
// Enumerate all dependencies.
|
||
//
|
||
if (dwType & CLUSTER_RESOURCE_ENUM_DEPENDS) {
|
||
i=0;
|
||
do {
|
||
Result = FmEnumResourceDependent(Resource,
|
||
i,
|
||
&Target);
|
||
if (Result == ERROR_SUCCESS) {
|
||
RealName = ApipGetObjectName( Target );
|
||
if (RealName != NULL) {
|
||
ApipAddToEnum(&Enum,
|
||
&Allocated,
|
||
RealName,
|
||
CLUSTER_RESOURCE_ENUM_DEPENDS);
|
||
MIDL_user_free(RealName);
|
||
}
|
||
OmDereferenceObject(Target);
|
||
++i;
|
||
}
|
||
} while ( Result == ERROR_SUCCESS );
|
||
|
||
}
|
||
|
||
//
|
||
// Enumerate all dependents
|
||
//
|
||
if (dwType & CLUSTER_RESOURCE_ENUM_PROVIDES) {
|
||
i=0;
|
||
do {
|
||
Result = FmEnumResourceProvider(Resource,
|
||
i,
|
||
&Target);
|
||
if (Result == ERROR_SUCCESS) {
|
||
RealName = ApipGetObjectName( Target );
|
||
if (RealName != NULL) {
|
||
ApipAddToEnum(&Enum,
|
||
&Allocated,
|
||
RealName,
|
||
CLUSTER_RESOURCE_ENUM_PROVIDES);
|
||
MIDL_user_free(RealName);
|
||
}
|
||
OmDereferenceObject(Target);
|
||
++i;
|
||
}
|
||
} while ( Result == ERROR_SUCCESS );
|
||
}
|
||
|
||
//
|
||
// Enumerate all possible nodes
|
||
//
|
||
if (dwType & CLUSTER_RESOURCE_ENUM_NODES) {
|
||
i=0;
|
||
do {
|
||
Result = FmEnumResourceNode(Resource,
|
||
i,
|
||
&Node);
|
||
if (Result == ERROR_SUCCESS) {
|
||
RealName = (LPWSTR)OmObjectName( Node );
|
||
if (RealName != NULL) {
|
||
ApipAddToEnum(&Enum,
|
||
&Allocated,
|
||
RealName,
|
||
CLUSTER_RESOURCE_ENUM_NODES);
|
||
}
|
||
OmDereferenceObject(Node);
|
||
++i;
|
||
}
|
||
} while ( Result == ERROR_SUCCESS );
|
||
}
|
||
|
||
*ReturnEnum = Enum;
|
||
return(ERROR_SUCCESS);
|
||
|
||
ErrorExit:
|
||
|
||
if (Enum != NULL) {
|
||
MIDL_user_free(Enum);
|
||
}
|
||
if (NewEnum != NULL) {
|
||
MIDL_user_free(NewEnum);
|
||
}
|
||
|
||
*ReturnEnum = NULL;
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiAddResourceNode(
|
||
IN HRES_RPC hResource,
|
||
IN HNODE_RPC hNode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds a node to the list of nodes where the specified resource
|
||
can be brought online.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose list of possible nodes is
|
||
to be modified.
|
||
|
||
hNode - Supplies the node to be added to the resource's list.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PNM_NODE Node;
|
||
DWORD Status;
|
||
DWORD dwUserModified;
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_NODE(Node, hNode);
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
//
|
||
// Call the FM to do the real work.
|
||
//
|
||
Status = FmChangeResourceNode(Resource, Node, TRUE);
|
||
if (Status != ERROR_SUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
//write out the fact that the user has explicitly set the
|
||
//resource possible node list
|
||
//
|
||
dwUserModified = 1;
|
||
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[API] s_ApiAddResourceNode: Setting UserModifiedPossibleNodeList key for resource %1!ws! \r\n",
|
||
OmObjectId(Resource));
|
||
|
||
DmSetValue( Resource->RegistryKey,
|
||
CLUSREG_NAME_RES_USER_MODIFIED_POSSIBLE_LIST,
|
||
REG_DWORD,
|
||
(LPBYTE)&dwUserModified,
|
||
sizeof(DWORD));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiRemoveResourceNode(
|
||
IN HRES_RPC hResource,
|
||
IN HNODE_RPC hNode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes a node from the list of nodes that can host the
|
||
specified resource. The resource must not be currently
|
||
online on the specified node.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource whose list of possible nodes is
|
||
to be modified.
|
||
|
||
hNode - Supplies the node to be removed from the resource's list.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PNM_NODE Node;
|
||
DWORD Status;
|
||
DWORD dwUserModified;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_NODE(Node, hNode);
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
|
||
//
|
||
// Call the FM to do the real work.
|
||
//
|
||
Status = FmChangeResourceNode(Resource, Node, FALSE);
|
||
if (Status != ERROR_SUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
//write out the fact that the user has explicitly set the
|
||
//resource possible node list
|
||
//
|
||
dwUserModified = 1;
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[API] s_ApiRemoveResourceNode: Setting UserModifiedPossibleNodeList key for resource %1!ws! \r\n",
|
||
OmObjectId(Resource));
|
||
|
||
DmSetValue( Resource->RegistryKey,
|
||
CLUSREG_NAME_RES_USER_MODIFIED_POSSIBLE_LIST,
|
||
REG_DWORD,
|
||
(LPBYTE)&dwUserModified,
|
||
sizeof(DWORD));
|
||
|
||
//SS: moved the write to the registry settings to the fm
|
||
// layer as well, this way it is truly transactional
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiCreateResourceType(
|
||
IN handle_t IDL_handle,
|
||
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:
|
||
|
||
IDL_handle - RPC binding handle, not used.
|
||
|
||
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.
|
||
|
||
dwLooksAlive - Supplies the default LooksAlive poll interval
|
||
for the new resource type in milliseconds.
|
||
|
||
dwIsAlive - Supplies the default IsAlive poll interval for
|
||
the new resource type in milliseconds.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
HDMKEY TypeKey = NULL;
|
||
DWORD Disposition;
|
||
DWORD dwClusterHighestVersion;
|
||
|
||
//
|
||
// Chittur Subbaraman (chitturs) - 2/8/2000
|
||
//
|
||
// If we are dealing with the mixed mode cluster, do the
|
||
// registry updates right here since the GUM handler won't do it.
|
||
//
|
||
NmGetClusterOperationalVersion( &dwClusterHighestVersion,
|
||
NULL,
|
||
NULL );
|
||
|
||
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
|
||
NT51_MAJOR_VERSION ) {
|
||
//
|
||
// Add the resource information to the registry. If the key does not already
|
||
// exist, then the name is unique and we can go ahead and call the FM to
|
||
// create the actual resource type object.
|
||
//
|
||
TypeKey = DmCreateKey(DmResourceTypesKey,
|
||
lpszTypeName,
|
||
0,
|
||
KEY_READ | KEY_WRITE,
|
||
NULL,
|
||
&Disposition);
|
||
if (TypeKey == NULL) {
|
||
return(GetLastError());
|
||
}
|
||
if (Disposition != REG_CREATED_NEW_KEY) {
|
||
DmCloseKey(TypeKey);
|
||
return(ERROR_ALREADY_EXISTS);
|
||
}
|
||
|
||
Status = DmSetValue(TypeKey,
|
||
CLUSREG_NAME_RESTYPE_DLL_NAME,
|
||
REG_SZ,
|
||
(CONST BYTE *)lpszDllName,
|
||
(lstrlenW(lpszDllName)+1)*sizeof(WCHAR));
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
Status = DmSetValue(TypeKey,
|
||
CLUSREG_NAME_RESTYPE_IS_ALIVE,
|
||
REG_DWORD,
|
||
(CONST BYTE *)&dwIsAlive,
|
||
sizeof(dwIsAlive));
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
Status = DmSetValue(TypeKey,
|
||
CLUSREG_NAME_RESTYPE_LOOKS_ALIVE,
|
||
REG_DWORD,
|
||
(CONST BYTE *)&dwLooksAlive,
|
||
sizeof(dwIsAlive));
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
Status = DmSetValue(TypeKey,
|
||
CLUSREG_NAME_RESTYPE_NAME,
|
||
REG_SZ,
|
||
(CONST BYTE *)lpszDisplayName,
|
||
(lstrlenW(lpszDisplayName)+1)*sizeof(WCHAR));
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
}
|
||
|
||
Status = FmCreateResourceType(lpszTypeName,
|
||
lpszDisplayName,
|
||
lpszDllName,
|
||
dwLooksAlive,
|
||
dwIsAlive);
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto error_exit;
|
||
}
|
||
|
||
if (TypeKey != NULL) {
|
||
DmCloseKey(TypeKey);
|
||
}
|
||
return(ERROR_SUCCESS);
|
||
|
||
error_exit:
|
||
if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
|
||
NT51_MAJOR_VERSION ) {
|
||
DmCloseKey(TypeKey);
|
||
DmDeleteKey(DmResourceTypesKey, lpszTypeName);
|
||
}
|
||
return(Status);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiDeleteResourceType(
|
||
IN handle_t IDL_handle,
|
||
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:
|
||
|
||
IDL_handle - RPC binding handle, not used.
|
||
|
||
lpszResourceTypeName - Supplies the name of the resource type to
|
||
be deleted.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
|
||
//
|
||
// Delete the resource from the FM. This will check to make sure no
|
||
// resources of the specified type exist and check that the resource
|
||
// is already installed.
|
||
//
|
||
Status = FmDeleteResourceType(lpszTypeName);
|
||
if (Status != ERROR_SUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Now remove the resource type from the registry.
|
||
//
|
||
DmDeleteTree(DmResourceTypesKey, lpszTypeName);
|
||
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
|
||
error_status_t
|
||
s_ApiChangeResourceGroup(
|
||
IN HRES_RPC hResource,
|
||
IN HGROUP_RPC hGroup
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Moves a resource from one group to another.
|
||
|
||
Arguments:
|
||
|
||
hResource - Supplies the resource to move.
|
||
|
||
hGroup - Supplies the new group that the resource should be in.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFM_RESOURCE Resource;
|
||
PFM_GROUP Group;
|
||
DWORD Status;
|
||
|
||
API_CHECK_INIT();
|
||
|
||
VALIDATE_RESOURCE_EXISTS(Resource, hResource);
|
||
VALIDATE_GROUP_EXISTS(Group, hGroup);
|
||
|
||
|
||
//
|
||
// Call the FM to do the real work.
|
||
//
|
||
Status = FmChangeResourceGroup(Resource, Group);
|
||
if (Status != ERROR_SUCCESS) {
|
||
goto FnExit;
|
||
}
|
||
|
||
FnExit:
|
||
return(Status);
|
||
}
|
||
|
||
/****
|
||
@func error_status_t | s_ApiCreateResTypeEnum | Enumerates the list of
|
||
nodes in which the resource type can be supported and
|
||
returns the list of nodes to the caller. The client-side
|
||
is responsible for freeing the allocated memory.
|
||
|
||
@parm IN handle_t | IDL_handle | RPC binding handle, not used.
|
||
@parm IN LPCWSTR | lpszTypeName | Name of the resource type.
|
||
@parm IN DWORD | dwType | Supplies the type of properties
|
||
to be enumerated.
|
||
@parm OUT PNM_NODE | ReturnEnum | Returns the requested objects.
|
||
|
||
@comm This routine helps enumerating all the nodes that a particular
|
||
resource type can be supported on.
|
||
|
||
@rdesc ERROR_SUCCESS on success. Win32 error code otherwise.
|
||
|
||
@xref
|
||
****/
|
||
error_status_t
|
||
s_ApiCreateResTypeEnum(
|
||
IN handle_t IDL_handle,
|
||
IN LPCWSTR lpszTypeName,
|
||
IN DWORD dwType,
|
||
OUT PENUM_LIST *ReturnEnum
|
||
)
|
||
{
|
||
DWORD Status;
|
||
DWORD Allocated = 0;
|
||
PENUM_LIST Enum = NULL;
|
||
DWORD i;
|
||
DWORD Result;
|
||
PFM_RESTYPE pResType = NULL;
|
||
PNM_NODE pNode;
|
||
LPWSTR RealName = NULL;
|
||
|
||
pResType = OmReferenceObjectById(ObjectTypeResType,
|
||
lpszTypeName);
|
||
|
||
if (dwType & ~CLUSTER_RESOURCE_TYPE_ENUM_ALL) {
|
||
Status = ERROR_INVALID_PARAMETER;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
Allocated = INITIAL_ENUM_LIST_ALLOCATION;
|
||
Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));
|
||
if (Enum == NULL) {
|
||
Status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
if (pResType == NULL) {
|
||
//
|
||
// The object cannot be found in the list !
|
||
//
|
||
Status = ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND;
|
||
goto ErrorExit;
|
||
}
|
||
|
||
Enum->EntryCount = 0;
|
||
|
||
//
|
||
// Enumerate all possible nodes
|
||
//
|
||
if (dwType & CLUSTER_RESOURCE_TYPE_ENUM_NODES) {
|
||
i=0;
|
||
do {
|
||
Result = FmEnumResourceTypeNode(pResType,
|
||
i,
|
||
&pNode);
|
||
if (Result == ERROR_SUCCESS) {
|
||
RealName = (LPWSTR)OmObjectName( pNode );
|
||
if (RealName != NULL) {
|
||
ApipAddToEnum(&Enum,
|
||
&Allocated,
|
||
RealName,
|
||
CLUSTER_RESOURCE_TYPE_ENUM_NODES);
|
||
}
|
||
OmDereferenceObject( pNode );
|
||
++i;
|
||
}
|
||
} while ( Result == ERROR_SUCCESS );
|
||
}
|
||
|
||
*ReturnEnum = Enum;
|
||
OmDereferenceObject( pResType );
|
||
return(ERROR_SUCCESS);
|
||
|
||
ErrorExit:
|
||
if (pResType != NULL) {
|
||
OmDereferenceObject( pResType );
|
||
}
|
||
if (Enum != NULL) {
|
||
MIDL_user_free(Enum);
|
||
}
|
||
|
||
*ReturnEnum = NULL;
|
||
return(Status);
|
||
}
|