554 lines
11 KiB
C
554 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
group.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains Group ID managment routines.
|
|||
|
|
|||
|
Group IDs identify an AFD_GROUP_ENTRY structure in a lookup table.
|
|||
|
Each AFD_GROUP_ENTRY contains a reference count and a type (either
|
|||
|
GroupTypeConstrained or GroupTypeUnconstrained). Free group IDs are
|
|||
|
linked together in a doubly-linked list. As group IDs are allocated,
|
|||
|
they are removed from this list. Once the free list becomes empty,
|
|||
|
the lookup table is grown appropriately.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Keith Moore (keithmo) 06-Jun-1996
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "afdp.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Private constants.
|
|||
|
//
|
|||
|
|
|||
|
#define AFD_GROUP_TABLE_GROWTH 32 // entries
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Private types.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _AFD_GROUP_ENTRY {
|
|||
|
union {
|
|||
|
LIST_ENTRY ListEntry;
|
|||
|
struct {
|
|||
|
AFD_GROUP_TYPE GroupType;
|
|||
|
LONG ReferenceCount;
|
|||
|
};
|
|||
|
};
|
|||
|
} AFD_GROUP_ENTRY, *PAFD_GROUP_ENTRY;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Private globals.
|
|||
|
//
|
|||
|
|
|||
|
PERESOURCE AfdGroupTableResource;
|
|||
|
PAFD_GROUP_ENTRY AfdGroupTable;
|
|||
|
LIST_ENTRY AfdFreeGroupList;
|
|||
|
LONG AfdGroupTableSize;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Private functions.
|
|||
|
//
|
|||
|
|
|||
|
PAFD_GROUP_ENTRY
|
|||
|
AfdMapGroupToEntry(
|
|||
|
IN LONG Group
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( INIT, AfdInitializeGroup )
|
|||
|
#pragma alloc_text( PAGE, AfdTerminateGroup )
|
|||
|
#pragma alloc_text( PAGE, AfdReferenceGroup )
|
|||
|
#pragma alloc_text( PAGE, AfdDereferenceGroup )
|
|||
|
#pragma alloc_text( PAGE, AfdGetGroup )
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AfdInitializeGroup(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initializes any globals necessary for the group ID package.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - TRUE if successful, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the group globals.
|
|||
|
//
|
|||
|
|
|||
|
AfdGroupTableResource = AFD_ALLOCATE_POOL_PRIORITY(
|
|||
|
NonPagedPool,
|
|||
|
sizeof(*AfdGroupTableResource),
|
|||
|
AFD_RESOURCE_POOL_TAG,
|
|||
|
HighPoolPriority
|
|||
|
);
|
|||
|
|
|||
|
if( AfdGroupTableResource == NULL ) {
|
|||
|
|
|||
|
return FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ExInitializeResourceLite( AfdGroupTableResource );
|
|||
|
|
|||
|
AfdGroupTable = NULL;
|
|||
|
InitializeListHead( &AfdFreeGroupList );
|
|||
|
AfdGroupTableSize = 0;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} // AfdInitializeGroup
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdTerminateGroup(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Destroys any globals created for the group ID package.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
if( AfdGroupTableResource != NULL ) {
|
|||
|
|
|||
|
ExDeleteResourceLite( AfdGroupTableResource );
|
|||
|
|
|||
|
AFD_FREE_POOL(
|
|||
|
AfdGroupTableResource,
|
|||
|
AFD_RESOURCE_POOL_TAG
|
|||
|
);
|
|||
|
|
|||
|
AfdGroupTableResource = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( AfdGroupTable != NULL ) {
|
|||
|
|
|||
|
AFD_FREE_POOL(
|
|||
|
AfdGroupTable,
|
|||
|
AFD_GROUP_POOL_TAG
|
|||
|
);
|
|||
|
|
|||
|
AfdGroupTable = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
InitializeListHead( &AfdFreeGroupList );
|
|||
|
AfdGroupTableSize = 0;
|
|||
|
|
|||
|
} // AfdTerminateGroup
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AfdReferenceGroup(
|
|||
|
IN LONG Group,
|
|||
|
OUT PAFD_GROUP_TYPE GroupType
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Bumps the reference count associated with the given group ID.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Group - The group ID to reference.
|
|||
|
|
|||
|
GroupType - Returns the type of the group.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PAFD_GROUP_ENTRY groupEntry;
|
|||
|
AFD_GROUP_TYPE groupType;
|
|||
|
|
|||
|
groupEntry = AfdMapGroupToEntry( Group );
|
|||
|
|
|||
|
if( groupEntry != NULL ) {
|
|||
|
|
|||
|
groupType = groupEntry->GroupType;
|
|||
|
|
|||
|
if( groupType == GroupTypeConstrained ||
|
|||
|
groupType == GroupTypeUnconstrained ) {
|
|||
|
|
|||
|
groupEntry->ReferenceCount++;
|
|||
|
*GroupType = groupType;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
groupEntry = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( AfdGroupTableResource );
|
|||
|
KeLeaveCriticalRegion ();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return (BOOLEAN)( groupEntry != NULL );
|
|||
|
|
|||
|
} // AfdReferenceGroup
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AfdDereferenceGroup(
|
|||
|
IN LONG Group
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Decrements the reference count associated with the given group ID.
|
|||
|
If the ref count drops to zero, the group ID is freed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Group - The group ID to dereference.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PAFD_GROUP_ENTRY groupEntry;
|
|||
|
AFD_GROUP_TYPE groupType;
|
|||
|
|
|||
|
groupEntry = AfdMapGroupToEntry( Group );
|
|||
|
|
|||
|
if( groupEntry != NULL ) {
|
|||
|
|
|||
|
groupType = groupEntry->GroupType;
|
|||
|
|
|||
|
if( groupType == GroupTypeConstrained ||
|
|||
|
groupType == GroupTypeUnconstrained ) {
|
|||
|
|
|||
|
ASSERT( groupEntry->ReferenceCount > 0 );
|
|||
|
groupEntry->ReferenceCount--;
|
|||
|
|
|||
|
if( groupEntry->ReferenceCount == 0 ) {
|
|||
|
|
|||
|
InsertTailList(
|
|||
|
&AfdFreeGroupList,
|
|||
|
&groupEntry->ListEntry
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
groupEntry = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( AfdGroupTableResource );
|
|||
|
KeLeaveCriticalRegion ();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return (BOOLEAN)( groupEntry != NULL );
|
|||
|
|
|||
|
} // AfdDereferenceGroup
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
AfdGetGroup(
|
|||
|
IN OUT PLONG Group,
|
|||
|
OUT PAFD_GROUP_TYPE GroupType
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Examines the incoming group. If is zero, then nothing is done. If it
|
|||
|
is SG_CONSTRAINED_GROUP, then a new constrained group ID is created.
|
|||
|
If it is SG_UNCONSTRAINED_GROUP, then a new unconstrained group ID is
|
|||
|
created. Otherwise, it must identify an existing group, so that group
|
|||
|
is referenced.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Group - Points to the group ID to examine/modify.
|
|||
|
|
|||
|
GroupType - Returns the type of the group.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - TRUE if successful, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
LONG groupValue;
|
|||
|
PAFD_GROUP_ENTRY groupEntry;
|
|||
|
PAFD_GROUP_ENTRY newGroupTable;
|
|||
|
LONG newGroupTableSize;
|
|||
|
LONG i;
|
|||
|
PLIST_ENTRY listEntry;
|
|||
|
|
|||
|
groupValue = *Group;
|
|||
|
|
|||
|
//
|
|||
|
// Zero means "no group", so just ignore it.
|
|||
|
//
|
|||
|
|
|||
|
if( groupValue == 0 ) {
|
|||
|
|
|||
|
*GroupType = GroupTypeNeither;
|
|||
|
return TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we're being asked to create a new group, do it.
|
|||
|
//
|
|||
|
|
|||
|
if( groupValue == SG_CONSTRAINED_GROUP ||
|
|||
|
groupValue == SG_UNCONSTRAINED_GROUP ) {
|
|||
|
|
|||
|
//
|
|||
|
// Lock the table.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the thread in which we execute cannot get
|
|||
|
// suspeneded in APC while we own the global resource.
|
|||
|
//
|
|||
|
KeEnterCriticalRegion ();
|
|||
|
ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
|
|||
|
|
|||
|
//
|
|||
|
// See if there's room at the inn.
|
|||
|
//
|
|||
|
|
|||
|
if( IsListEmpty( &AfdFreeGroupList ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// No room, we'll need to create/expand the table.
|
|||
|
//
|
|||
|
|
|||
|
newGroupTableSize = AfdGroupTableSize + AFD_GROUP_TABLE_GROWTH;
|
|||
|
|
|||
|
newGroupTable = AFD_ALLOCATE_POOL(
|
|||
|
PagedPool,
|
|||
|
newGroupTableSize * sizeof(AFD_GROUP_ENTRY),
|
|||
|
AFD_GROUP_POOL_TAG
|
|||
|
);
|
|||
|
|
|||
|
if( newGroupTable == NULL ) {
|
|||
|
|
|||
|
ExReleaseResourceLite( AfdGroupTableResource );
|
|||
|
KeLeaveCriticalRegion ();
|
|||
|
return FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( AfdGroupTable == NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// This is the initial table allocation, so reserve the
|
|||
|
// first three entries (0, SG_UNCONSTRAINED_GROUP, and
|
|||
|
// SG_CONSTRAINED_GROUP).
|
|||
|
//
|
|||
|
|
|||
|
for( ;
|
|||
|
AfdGroupTableSize <= SG_CONSTRAINED_GROUP ||
|
|||
|
AfdGroupTableSize <= SG_UNCONSTRAINED_GROUP ;
|
|||
|
AfdGroupTableSize++ ) {
|
|||
|
|
|||
|
newGroupTable[AfdGroupTableSize].ReferenceCount = 0;
|
|||
|
newGroupTable[AfdGroupTableSize].GroupType = GroupTypeNeither;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the old table into the new table, then free the
|
|||
|
// old table.
|
|||
|
//
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
newGroupTable,
|
|||
|
AfdGroupTable,
|
|||
|
AfdGroupTableSize * sizeof(AFD_GROUP_ENTRY)
|
|||
|
);
|
|||
|
|
|||
|
AFD_FREE_POOL(
|
|||
|
AfdGroupTable,
|
|||
|
AFD_GROUP_POOL_TAG
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add the new entries to the free list.
|
|||
|
//
|
|||
|
|
|||
|
for( i = newGroupTableSize - 1 ; i >= AfdGroupTableSize ; i-- ) {
|
|||
|
|
|||
|
InsertHeadList(
|
|||
|
&AfdFreeGroupList,
|
|||
|
&newGroupTable[i].ListEntry
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
AfdGroupTable = newGroupTable;
|
|||
|
AfdGroupTableSize = newGroupTableSize;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Pull the next free entry off the list.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( !IsListEmpty( &AfdFreeGroupList ) );
|
|||
|
|
|||
|
listEntry = RemoveHeadList( &AfdFreeGroupList );
|
|||
|
|
|||
|
groupEntry = CONTAINING_RECORD(
|
|||
|
listEntry,
|
|||
|
AFD_GROUP_ENTRY,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
groupEntry->ReferenceCount = 1;
|
|||
|
groupEntry->GroupType = (AFD_GROUP_TYPE)groupValue;
|
|||
|
|
|||
|
*Group = (LONG)( groupEntry - AfdGroupTable );
|
|||
|
*GroupType = groupEntry->GroupType;
|
|||
|
|
|||
|
ExReleaseResourceLite( AfdGroupTableResource );
|
|||
|
KeLeaveCriticalRegion ();
|
|||
|
return TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Otherwise, just reference the group.
|
|||
|
//
|
|||
|
|
|||
|
return AfdReferenceGroup( groupValue, GroupType );
|
|||
|
|
|||
|
} // AfdGetGroup
|
|||
|
|
|||
|
|
|||
|
PAFD_GROUP_ENTRY
|
|||
|
AfdMapGroupToEntry(
|
|||
|
IN LONG Group
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Maps the given group ID to the corresponding AFD_GROUP_ENTRY structure.
|
|||
|
|
|||
|
N.B. This routine returns with AfdGroupTableResource held if successful.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Group - The group ID to map.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PAFD_GROUP_ENTRY - The entry corresponding to the group ID if successful,
|
|||
|
NULL otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PAFD_GROUP_ENTRY groupEntry;
|
|||
|
|
|||
|
//
|
|||
|
// Lock the table.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the thread in which we execute cannot get
|
|||
|
// suspeneded in APC while we own the global resource.
|
|||
|
//
|
|||
|
KeEnterCriticalRegion ();
|
|||
|
ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
|
|||
|
|
|||
|
//
|
|||
|
// Validate the group ID.
|
|||
|
//
|
|||
|
|
|||
|
if( Group > 0 && Group < AfdGroupTableSize ) {
|
|||
|
|
|||
|
groupEntry = AfdGroupTable + Group;
|
|||
|
|
|||
|
//
|
|||
|
// The group ID is within legal range. Ensure it's in use.
|
|||
|
// In the AFD_GROUP_ENTRY structure, the GroupType field is
|
|||
|
// overlayed with ListEntry.Flink due to the internal union.
|
|||
|
// We can use this knowledge to quickly validate that this
|
|||
|
// entry is in use.
|
|||
|
//
|
|||
|
|
|||
|
if( groupEntry->GroupType == GroupTypeConstrained ||
|
|||
|
groupEntry->GroupType == GroupTypeUnconstrained ) {
|
|||
|
|
|||
|
return groupEntry;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Invalid group ID, fail it.
|
|||
|
//
|
|||
|
|
|||
|
ExReleaseResourceLite( AfdGroupTableResource );
|
|||
|
KeLeaveCriticalRegion ();
|
|||
|
return NULL;
|
|||
|
|
|||
|
} // AfdMapGroupToEntry
|
|||
|
|