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.
803 lines
19 KiB
803 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1996-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fmval.c
|
|
|
|
Abstract:
|
|
|
|
Cluster manager api validation/support routines.
|
|
|
|
Author:
|
|
|
|
Sunita Shrivastava (sunitas) 29-April-1999.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "fmp.h"
|
|
|
|
#define LOG_MODULE FMVAL
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Validation routines for Group operations.
|
|
//
|
|
////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
FmpValOnlineGroup(
|
|
IN PFM_GROUP Group
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine before group is brought online.
|
|
|
|
Arguments:
|
|
|
|
Group - Supplies a pointer to the group structure to bring online.
|
|
|
|
Comments:
|
|
|
|
Is called with the localgroup lock held
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PLIST_ENTRY listEntry;
|
|
|
|
|
|
//if the group has been marked for delete, then fail this call
|
|
if (!IS_VALID_FM_GROUP(Group))
|
|
{
|
|
dwStatus = ERROR_GROUP_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Make sure the owning node can run the group.
|
|
//
|
|
if ( !FmpInPreferredList( Group, Group->OwnerNode ) )
|
|
{
|
|
dwStatus = ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Make sure the owning node is not paused.
|
|
//
|
|
if (NmGetNodeState(Group->OwnerNode) == ClusterNodePaused)
|
|
{
|
|
dwStatus = ERROR_SHARING_PAUSED;
|
|
goto FnExit;
|
|
}
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
|
|
} // FmpValOnlineGroup
|
|
|
|
|
|
DWORD
|
|
FmpValMoveGroup(
|
|
IN PFM_GROUP Group,
|
|
IN PNM_NODE DestinationNode OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine for group move.
|
|
|
|
Arguments:
|
|
|
|
Group - Supplies a pointer to the group structure to move.
|
|
|
|
DestinationNode - Supplies the node object to move the group to. If not
|
|
present, then move it to THE OTHER node.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
//if the group has been marked for delete, then fail this call
|
|
if (!IS_VALID_FM_GROUP(Group))
|
|
{
|
|
dwStatus = ERROR_GROUP_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( FmpIsGroupPending(Group) )
|
|
{
|
|
dwStatus = ERROR_GROUP_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( Group->OwnerNode == NULL )
|
|
{
|
|
dwStatus = ERROR_HOST_NODE_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
|
|
} // FmpValMoveGroup
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Validation routines for resource operations
|
|
//
|
|
////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
FmpValCreateResource(
|
|
IN PFM_GROUP Group,
|
|
IN LPWSTR ResourceId,
|
|
IN LPCWSTR ResourceName,
|
|
OUT PGUM_CREATE_RESOURCE *ppGumResource,
|
|
OUT PDWORD pdwBufSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine for resource creation.
|
|
|
|
Arguments:
|
|
|
|
Group - Supplies the group in which this resource belongs.
|
|
|
|
ResourceId - Supplies the Id of the resource to create.
|
|
|
|
ResourceName - Supplies the 'user-friendly' name of the resource.
|
|
|
|
ppGumResource - Message buffer to hold resource info.
|
|
|
|
pdwBufSize - Message buffer size.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PFM_RESOURCE Resource;
|
|
LPCWSTR GroupId;
|
|
PGUM_CREATE_RESOURCE GumResource;
|
|
DWORD GroupIdLen;
|
|
DWORD ResourceIdLen;
|
|
DWORD ResourceNameLen;
|
|
DWORD BufSize;
|
|
HDMKEY ResourceKey;
|
|
HDMKEY ParamsKey;
|
|
DWORD Disposition;
|
|
|
|
*ppGumResource = NULL;
|
|
*pdwBufSize = 0;
|
|
|
|
//
|
|
// First create the parameters field.
|
|
//
|
|
ResourceKey = DmOpenKey( DmResourcesKey,
|
|
ResourceId,
|
|
MAXIMUM_ALLOWED );
|
|
if ( ResourceKey == NULL )
|
|
{
|
|
ClRtlLogPrint(LOG_NOISE,
|
|
"[FM] CreateResource: Failed to open registry key for %1!ws!, status = %2!u!.\n",
|
|
ResourceId,
|
|
GetLastError() );
|
|
dwStatus = GetLastError();
|
|
goto FnExit;
|
|
}
|
|
|
|
ParamsKey = DmCreateKey( ResourceKey,
|
|
CLUSREG_KEYNAME_PARAMETERS,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&Disposition );
|
|
if ( ParamsKey != NULL )
|
|
{
|
|
DmCloseKey( ParamsKey );
|
|
}
|
|
DmCloseKey( ResourceKey );
|
|
|
|
//
|
|
// Allocate a message buffer.
|
|
//
|
|
GroupId = OmObjectId(Group);
|
|
GroupIdLen = (lstrlenW(GroupId)+1) * sizeof(WCHAR);
|
|
ResourceIdLen = (lstrlenW(ResourceId)+1) * sizeof(WCHAR);
|
|
ResourceNameLen = (lstrlenW(ResourceName)+1) * sizeof(WCHAR);
|
|
BufSize = sizeof(GUM_CREATE_RESOURCE) - sizeof(WCHAR) +
|
|
GroupIdLen + ResourceIdLen + ResourceNameLen;
|
|
GumResource = LocalAlloc(LMEM_FIXED, BufSize);
|
|
if (GumResource == NULL) {
|
|
CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Fill in message buffer.
|
|
//
|
|
GumResource->Resource = NULL;
|
|
GumResource->GroupIdLen = GroupIdLen;
|
|
GumResource->ResourceIdLen = ResourceIdLen;
|
|
CopyMemory(GumResource->GroupId, GroupId, GroupIdLen);
|
|
CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen,
|
|
ResourceId,
|
|
ResourceIdLen);
|
|
CopyMemory((PCHAR)GumResource->GroupId + GroupIdLen + ResourceIdLen,
|
|
ResourceName,
|
|
ResourceNameLen);
|
|
|
|
|
|
|
|
*ppGumResource = GumResource;
|
|
*pdwBufSize = BufSize;
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
|
|
} // FmpValCreateResource
|
|
|
|
|
|
|
|
DWORD
|
|
FmpValDeleteResource(
|
|
IN PFM_RESOURCE pResource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine for delete resource.
|
|
|
|
Arguments:
|
|
|
|
Resource - Supplies the resource to delete.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
|
|
//
|
|
// Check if this is the quorum resource.
|
|
//
|
|
if ( pResource->QuorumResource )
|
|
{
|
|
dwStatus = ERROR_QUORUM_RESOURCE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//other core resources cannot be deleted either
|
|
if (pResource->ExFlags & CLUS_FLAG_CORE)
|
|
{
|
|
dwStatus = ERROR_CORE_RESOURCE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Check the state of the resource, before attempting to delete it.
|
|
// It must be offline or failed in order to perform the delete.
|
|
//
|
|
if ((pResource->State != ClusterResourceOffline) &&
|
|
(pResource->State != ClusterResourceFailed))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_ONLINE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Check whether this resource provides for any other resources.
|
|
// If so, it cannot be deleted.
|
|
//
|
|
if (!IsListEmpty(&pResource->ProvidesFor))
|
|
{
|
|
dwStatus = ERROR_DEPENDENT_RESOURCE_EXISTS;
|
|
goto FnExit;
|
|
}
|
|
|
|
if (pResource->Group->MovingList)
|
|
{
|
|
dwStatus = ERROR_INVALID_STATE;
|
|
goto FnExit;
|
|
}
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
|
|
} // FmpValDeleteResource
|
|
|
|
|
|
DWORD
|
|
FmpValOnlineResource(
|
|
IN PFM_RESOURCE pResource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine validates if a resource can be brought online.
|
|
|
|
Arguments:
|
|
|
|
Resource - A pointer to the resource to bring online.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
//if the resource has been marked for delete, then dont let
|
|
//it be brought online
|
|
if (!IS_VALID_FM_RESOURCE(pResource))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Check if the resource has been initialized. If not, attempt
|
|
// to initialize the resource now.
|
|
//
|
|
if ( pResource->Monitor == NULL )
|
|
{
|
|
dwStatus = FmpInitializeResource( pResource, TRUE );
|
|
}
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
} // FmpValOnlineResource
|
|
|
|
|
|
DWORD
|
|
FmpValOfflineResource(
|
|
IN PFM_RESOURCE pResource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine validates if a given resource can be taken offline.
|
|
|
|
Arguments:
|
|
|
|
Resource - A pointer to the resource to take offline.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
|
|
//if the resource has been marked for delete, then fail this call
|
|
if (!IS_VALID_FM_RESOURCE(pResource))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Check if this is the quorum resource.
|
|
//
|
|
if ( pResource->QuorumResource )
|
|
{
|
|
dwStatus = ERROR_QUORUM_RESOURCE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Check if the resource has been initialized. If not, return
|
|
// success because the resource is not online.
|
|
//
|
|
if ( pResource->Monitor == NULL )
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Chittur Subbaraman (chitturs) - 4/8/99
|
|
//
|
|
// Don't attempt to do anything if the resource has failed. You could
|
|
// get into some funny cases in which the resource switches between
|
|
// offline pending and failed states for ever.
|
|
//
|
|
if ( pResource->State == ClusterResourceFailed )
|
|
{
|
|
dwStatus = ERROR_INVALID_STATE;
|
|
goto FnExit;
|
|
}
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
|
|
} // FmpValOfflineResource
|
|
|
|
|
|
|
|
DWORD
|
|
FmpValAddResourceDependency(
|
|
IN PFM_RESOURCE pResource,
|
|
IN PFM_RESOURCE pDependentResource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine for dependency addition.
|
|
|
|
Arguments:
|
|
|
|
Resource - The resource to add the dependent resource.
|
|
|
|
DependentResource - The dependent resource.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
//if the resource has been marked for delete, then dont let
|
|
//it be brought online
|
|
if (!IS_VALID_FM_RESOURCE(pResource))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
if (pResource->QuorumResource)
|
|
{
|
|
dwStatus = ERROR_DEPENDENCY_NOT_ALLOWED;
|
|
goto FnExit;
|
|
}
|
|
//
|
|
// 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 ((pResource->Group != pDependentResource->Group) ||
|
|
(pResource == pDependentResource))
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
goto FnExit;
|
|
}
|
|
|
|
// The resource to which the dependency is being added must be offline
|
|
// Otherwise, it looks like the dependency is in effect when the depending
|
|
// resource was not really brought online at the time the dependency existed
|
|
// must also be offline or failed.
|
|
// SS: For instance if a network name is dependent on two ip addresesses and
|
|
// is online and a third ip address resource dependency is added, the
|
|
// network name must be brought offline and online for the dependency
|
|
// to be truly in effect
|
|
//
|
|
if ((pResource->State != ClusterResourceOffline) &&
|
|
(pResource->State != ClusterResourceFailed))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_ONLINE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Make sure that we don't have any circular dependencies!
|
|
//
|
|
if ( FmDependentResource( pDependentResource, pResource, FALSE ) )
|
|
{
|
|
dwStatus = ERROR_CIRCULAR_DEPENDENCY;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Make sure that this dependency does not already exist!
|
|
//
|
|
if ( FmDependentResource(pResource, pDependentResource, TRUE))
|
|
{
|
|
dwStatus = ERROR_DEPENDENCY_ALREADY_EXISTS;
|
|
goto FnExit;
|
|
}
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
|
|
} // FmpValAddResourceDependency
|
|
|
|
|
|
DWORD
|
|
FmpValChangeResourceNode(
|
|
IN PFM_RESOURCE pResource,
|
|
IN LPCWSTR pszNodeId,
|
|
IN BOOL bAdd,
|
|
OUT PGUM_CHANGE_POSSIBLE_NODE *ppGumChange,
|
|
OUT PDWORD pdwBufSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine for changing the possible owner node of a resource.
|
|
|
|
Arguments:
|
|
|
|
pResource - A pointer to the resource structure.
|
|
|
|
pszNodeId - A pointer to the node id
|
|
|
|
bAdd - Indicates add or remove
|
|
|
|
ppGumChange - Message buffer to hold the resource info
|
|
|
|
pdwBufSize - Size of the message buffer
|
|
|
|
Comments:
|
|
|
|
Lock must be held when this routine is called
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if the validation is successful.
|
|
|
|
A Win32 error code if the validation fails.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PLIST_ENTRY pListEntry;
|
|
PRESTYPE_POSSIBLE_ENTRY pResTypePosEntry = NULL;
|
|
BOOL bNodeSupportsResType = FALSE;
|
|
LPCWSTR pszResourceId;
|
|
DWORD dwResourceLen;
|
|
DWORD dwNodeLen;
|
|
DWORD dwBufSize;
|
|
PGUM_CHANGE_POSSIBLE_NODE pGumChange;
|
|
|
|
*ppGumChange = NULL;
|
|
*pdwBufSize = 0;
|
|
|
|
|
|
//if the resource has been marked for delete, then perform
|
|
//any operations on it
|
|
if (!IS_VALID_FM_RESOURCE(pResource))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( pResource->QuorumResource )
|
|
{
|
|
dwStatus = ERROR_INVALID_OPERATION_ON_QUORUM;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// We can't allow the owner node to be removed if the state
|
|
// of the resource or the group is not offline or failed.
|
|
//
|
|
if ( !bAdd &&
|
|
(lstrcmpi(NodeId, OmObjectId(NmLocalNode)) == 0) &&
|
|
(((pResource->State != ClusterResourceOffline) &&
|
|
(pResource->State != ClusterResourceFailed)) ||
|
|
(FmpGetGroupState( pResource->Group, TRUE ) != ClusterGroupOffline)) )
|
|
{
|
|
dwStatus = ERROR_INVALID_STATE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//make sure the node is on the list of possible nodes for this
|
|
// resource type
|
|
if (bAdd)
|
|
{
|
|
pListEntry = &(pResource->Type->PossibleNodeList);
|
|
for (pListEntry = pListEntry->Flink;
|
|
pListEntry != &(pResource->Type->PossibleNodeList);
|
|
pListEntry = pListEntry->Flink)
|
|
{
|
|
|
|
pResTypePosEntry = CONTAINING_RECORD(pListEntry, RESTYPE_POSSIBLE_ENTRY,
|
|
PossibleLinkage);
|
|
|
|
if (!lstrcmpW(OmObjectId(pResTypePosEntry->PossibleNode), pszNodeId))
|
|
{
|
|
bNodeSupportsResType = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (!bNodeSupportsResType)
|
|
{
|
|
dwStatus = ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED;
|
|
goto FnExit;
|
|
}
|
|
}
|
|
|
|
pszResourceId = OmObjectId(pResource);
|
|
dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
|
|
|
|
dwNodeLen = (lstrlenW(pszNodeId)+1)*sizeof(WCHAR);
|
|
|
|
dwBufSize = sizeof(GUM_CHANGE_POSSIBLE_NODE) - sizeof(WCHAR) +
|
|
dwResourceLen + dwNodeLen;
|
|
pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize);
|
|
if (pGumChange == NULL) {
|
|
CsInconsistencyHalt( ERROR_NOT_ENOUGH_MEMORY );
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
pGumChange->ResourceIdLen = dwResourceLen;
|
|
CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen);
|
|
CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen,
|
|
pszNodeId,
|
|
dwNodeLen);
|
|
|
|
|
|
*ppGumChange = pGumChange;
|
|
*pdwBufSize = dwBufSize;
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
} // FmpValChangeResourceNode
|
|
|
|
|
|
DWORD
|
|
FmpValChangeResourceGroup(
|
|
IN PFM_RESOURCE pResource,
|
|
IN PFM_GROUP pNewGroup,
|
|
OUT PGUM_CHANGE_GROUP *ppGumChange,
|
|
OUT LPDWORD pdwBufSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validation routine for changing a resource's group.
|
|
|
|
Arguments:
|
|
|
|
pResource - Pointer to the resource structure
|
|
|
|
pNewGroup - Pointer to the group to which the resource is moved to
|
|
|
|
ppGumChange - Message buffer to hold the resource info
|
|
|
|
pdwBufSize - Size of the message buffer
|
|
|
|
Comments:
|
|
|
|
Lock must be held when this routine is called
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS if validation is successful.
|
|
|
|
A Win32 error code otherwise.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwBufSize;
|
|
LPCWSTR pszResourceId;
|
|
DWORD dwResourceLen;
|
|
LPCWSTR pszGroupId;
|
|
DWORD dwGroupLen;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PGUM_CHANGE_GROUP pGumChange;
|
|
|
|
*pdwBufSize = 0;
|
|
*ppGumChange = NULL;
|
|
|
|
// we need to validate here as well
|
|
// this is called by the server side
|
|
// this will help avoid a gum call if things have changed
|
|
// since the request started from the originator
|
|
// and got to the server
|
|
//if the resource has been marked for delete, then fail this call
|
|
if (!IS_VALID_FM_RESOURCE(pResource))
|
|
{
|
|
dwStatus = ERROR_RESOURCE_NOT_AVAILABLE;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Check if we're moving to same group.
|
|
//
|
|
if (pResource->Group == pNewGroup)
|
|
{
|
|
dwStatus = ERROR_ALREADY_EXISTS;
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// For now... both Groups must be owned by the same node.
|
|
//
|
|
if ( pResource->Group->OwnerNode != pNewGroup->OwnerNode )
|
|
{
|
|
dwStatus = ERROR_HOST_NODE_NOT_GROUP_OWNER;
|
|
goto FnExit;
|
|
}
|
|
|
|
|
|
pszResourceId = OmObjectId(pResource);
|
|
dwResourceLen = (lstrlenW(pszResourceId)+1)*sizeof(WCHAR);
|
|
|
|
pszGroupId = OmObjectId(pNewGroup);
|
|
dwGroupLen = (lstrlenW(pszGroupId)+1)*sizeof(WCHAR);
|
|
|
|
dwBufSize = sizeof(GUM_CHANGE_GROUP) - sizeof(WCHAR) + dwResourceLen + dwGroupLen;
|
|
pGumChange = LocalAlloc(LMEM_FIXED, dwBufSize);
|
|
if (pGumChange == NULL) {
|
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto FnExit;
|
|
}
|
|
|
|
pGumChange->ResourceIdLen = dwResourceLen;
|
|
CopyMemory(pGumChange->ResourceId, pszResourceId, dwResourceLen);
|
|
CopyMemory((PCHAR)pGumChange->ResourceId + dwResourceLen,
|
|
pszGroupId,
|
|
dwGroupLen);
|
|
|
|
*ppGumChange = pGumChange;
|
|
*pdwBufSize = dwBufSize;
|
|
|
|
FnExit:
|
|
return(dwStatus);
|
|
} // FmpValChangeResourceGroup
|
|
|