Leaked source code of windows server 2003
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.

553 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. group.c
  5. Abstract:
  6. This module contains Group ID managment routines.
  7. Group IDs identify an AFD_GROUP_ENTRY structure in a lookup table.
  8. Each AFD_GROUP_ENTRY contains a reference count and a type (either
  9. GroupTypeConstrained or GroupTypeUnconstrained). Free group IDs are
  10. linked together in a doubly-linked list. As group IDs are allocated,
  11. they are removed from this list. Once the free list becomes empty,
  12. the lookup table is grown appropriately.
  13. Author:
  14. Keith Moore (keithmo) 06-Jun-1996
  15. Revision History:
  16. --*/
  17. #include "afdp.h"
  18. //
  19. // Private constants.
  20. //
  21. #define AFD_GROUP_TABLE_GROWTH 32 // entries
  22. //
  23. // Private types.
  24. //
  25. typedef struct _AFD_GROUP_ENTRY {
  26. union {
  27. LIST_ENTRY ListEntry;
  28. struct {
  29. AFD_GROUP_TYPE GroupType;
  30. LONG ReferenceCount;
  31. };
  32. };
  33. } AFD_GROUP_ENTRY, *PAFD_GROUP_ENTRY;
  34. //
  35. // Private globals.
  36. //
  37. PERESOURCE AfdGroupTableResource;
  38. PAFD_GROUP_ENTRY AfdGroupTable;
  39. LIST_ENTRY AfdFreeGroupList;
  40. LONG AfdGroupTableSize;
  41. //
  42. // Private functions.
  43. //
  44. PAFD_GROUP_ENTRY
  45. AfdMapGroupToEntry(
  46. IN LONG Group
  47. );
  48. #ifdef ALLOC_PRAGMA
  49. #pragma alloc_text( INIT, AfdInitializeGroup )
  50. #pragma alloc_text( PAGE, AfdTerminateGroup )
  51. #pragma alloc_text( PAGE, AfdReferenceGroup )
  52. #pragma alloc_text( PAGE, AfdDereferenceGroup )
  53. #pragma alloc_text( PAGE, AfdGetGroup )
  54. #endif
  55. BOOLEAN
  56. AfdInitializeGroup(
  57. VOID
  58. )
  59. /*++
  60. Routine Description:
  61. Initializes any globals necessary for the group ID package.
  62. Return Value:
  63. BOOLEAN - TRUE if successful, FALSE otherwise.
  64. --*/
  65. {
  66. //
  67. // Initialize the group globals.
  68. //
  69. AfdGroupTableResource = AFD_ALLOCATE_POOL_PRIORITY(
  70. NonPagedPool,
  71. sizeof(*AfdGroupTableResource),
  72. AFD_RESOURCE_POOL_TAG,
  73. HighPoolPriority
  74. );
  75. if( AfdGroupTableResource == NULL ) {
  76. return FALSE;
  77. }
  78. ExInitializeResourceLite( AfdGroupTableResource );
  79. AfdGroupTable = NULL;
  80. InitializeListHead( &AfdFreeGroupList );
  81. AfdGroupTableSize = 0;
  82. return TRUE;
  83. } // AfdInitializeGroup
  84. VOID
  85. AfdTerminateGroup(
  86. VOID
  87. )
  88. /*++
  89. Routine Description:
  90. Destroys any globals created for the group ID package.
  91. --*/
  92. {
  93. if( AfdGroupTableResource != NULL ) {
  94. ExDeleteResourceLite( AfdGroupTableResource );
  95. AFD_FREE_POOL(
  96. AfdGroupTableResource,
  97. AFD_RESOURCE_POOL_TAG
  98. );
  99. AfdGroupTableResource = NULL;
  100. }
  101. if( AfdGroupTable != NULL ) {
  102. AFD_FREE_POOL(
  103. AfdGroupTable,
  104. AFD_GROUP_POOL_TAG
  105. );
  106. AfdGroupTable = NULL;
  107. }
  108. InitializeListHead( &AfdFreeGroupList );
  109. AfdGroupTableSize = 0;
  110. } // AfdTerminateGroup
  111. BOOLEAN
  112. AfdReferenceGroup(
  113. IN LONG Group,
  114. OUT PAFD_GROUP_TYPE GroupType
  115. )
  116. /*++
  117. Routine Description:
  118. Bumps the reference count associated with the given group ID.
  119. Arguments:
  120. Group - The group ID to reference.
  121. GroupType - Returns the type of the group.
  122. Returns:
  123. BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
  124. --*/
  125. {
  126. PAFD_GROUP_ENTRY groupEntry;
  127. AFD_GROUP_TYPE groupType;
  128. groupEntry = AfdMapGroupToEntry( Group );
  129. if( groupEntry != NULL ) {
  130. groupType = groupEntry->GroupType;
  131. if( groupType == GroupTypeConstrained ||
  132. groupType == GroupTypeUnconstrained ) {
  133. groupEntry->ReferenceCount++;
  134. *GroupType = groupType;
  135. } else {
  136. groupEntry = NULL;
  137. }
  138. ExReleaseResourceLite( AfdGroupTableResource );
  139. KeLeaveCriticalRegion ();
  140. }
  141. return (BOOLEAN)( groupEntry != NULL );
  142. } // AfdReferenceGroup
  143. BOOLEAN
  144. AfdDereferenceGroup(
  145. IN LONG Group
  146. )
  147. /*++
  148. Routine Description:
  149. Decrements the reference count associated with the given group ID.
  150. If the ref count drops to zero, the group ID is freed.
  151. Arguments:
  152. Group - The group ID to dereference.
  153. Returns:
  154. BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
  155. --*/
  156. {
  157. PAFD_GROUP_ENTRY groupEntry;
  158. AFD_GROUP_TYPE groupType;
  159. groupEntry = AfdMapGroupToEntry( Group );
  160. if( groupEntry != NULL ) {
  161. groupType = groupEntry->GroupType;
  162. if( groupType == GroupTypeConstrained ||
  163. groupType == GroupTypeUnconstrained ) {
  164. ASSERT( groupEntry->ReferenceCount > 0 );
  165. groupEntry->ReferenceCount--;
  166. if( groupEntry->ReferenceCount == 0 ) {
  167. InsertTailList(
  168. &AfdFreeGroupList,
  169. &groupEntry->ListEntry
  170. );
  171. }
  172. } else {
  173. groupEntry = NULL;
  174. }
  175. ExReleaseResourceLite( AfdGroupTableResource );
  176. KeLeaveCriticalRegion ();
  177. }
  178. return (BOOLEAN)( groupEntry != NULL );
  179. } // AfdDereferenceGroup
  180. BOOLEAN
  181. AfdGetGroup(
  182. IN OUT PLONG Group,
  183. OUT PAFD_GROUP_TYPE GroupType
  184. )
  185. /*++
  186. Routine Description:
  187. Examines the incoming group. If is zero, then nothing is done. If it
  188. is SG_CONSTRAINED_GROUP, then a new constrained group ID is created.
  189. If it is SG_UNCONSTRAINED_GROUP, then a new unconstrained group ID is
  190. created. Otherwise, it must identify an existing group, so that group
  191. is referenced.
  192. Arguments:
  193. Group - Points to the group ID to examine/modify.
  194. GroupType - Returns the type of the group.
  195. Return Value:
  196. BOOLEAN - TRUE if successful, FALSE otherwise.
  197. --*/
  198. {
  199. LONG groupValue;
  200. PAFD_GROUP_ENTRY groupEntry;
  201. PAFD_GROUP_ENTRY newGroupTable;
  202. LONG newGroupTableSize;
  203. LONG i;
  204. PLIST_ENTRY listEntry;
  205. groupValue = *Group;
  206. //
  207. // Zero means "no group", so just ignore it.
  208. //
  209. if( groupValue == 0 ) {
  210. *GroupType = GroupTypeNeither;
  211. return TRUE;
  212. }
  213. //
  214. // If we're being asked to create a new group, do it.
  215. //
  216. if( groupValue == SG_CONSTRAINED_GROUP ||
  217. groupValue == SG_UNCONSTRAINED_GROUP ) {
  218. //
  219. // Lock the table.
  220. //
  221. //
  222. // Make sure the thread in which we execute cannot get
  223. // suspeneded in APC while we own the global resource.
  224. //
  225. KeEnterCriticalRegion ();
  226. ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
  227. //
  228. // See if there's room at the inn.
  229. //
  230. if( IsListEmpty( &AfdFreeGroupList ) ) {
  231. //
  232. // No room, we'll need to create/expand the table.
  233. //
  234. newGroupTableSize = AfdGroupTableSize + AFD_GROUP_TABLE_GROWTH;
  235. newGroupTable = AFD_ALLOCATE_POOL(
  236. PagedPool,
  237. newGroupTableSize * sizeof(AFD_GROUP_ENTRY),
  238. AFD_GROUP_POOL_TAG
  239. );
  240. if( newGroupTable == NULL ) {
  241. ExReleaseResourceLite( AfdGroupTableResource );
  242. KeLeaveCriticalRegion ();
  243. return FALSE;
  244. }
  245. if( AfdGroupTable == NULL ) {
  246. //
  247. // This is the initial table allocation, so reserve the
  248. // first three entries (0, SG_UNCONSTRAINED_GROUP, and
  249. // SG_CONSTRAINED_GROUP).
  250. //
  251. for( ;
  252. AfdGroupTableSize <= SG_CONSTRAINED_GROUP ||
  253. AfdGroupTableSize <= SG_UNCONSTRAINED_GROUP ;
  254. AfdGroupTableSize++ ) {
  255. newGroupTable[AfdGroupTableSize].ReferenceCount = 0;
  256. newGroupTable[AfdGroupTableSize].GroupType = GroupTypeNeither;
  257. }
  258. } else {
  259. //
  260. // Copy the old table into the new table, then free the
  261. // old table.
  262. //
  263. RtlCopyMemory(
  264. newGroupTable,
  265. AfdGroupTable,
  266. AfdGroupTableSize * sizeof(AFD_GROUP_ENTRY)
  267. );
  268. AFD_FREE_POOL(
  269. AfdGroupTable,
  270. AFD_GROUP_POOL_TAG
  271. );
  272. }
  273. //
  274. // Add the new entries to the free list.
  275. //
  276. for( i = newGroupTableSize - 1 ; i >= AfdGroupTableSize ; i-- ) {
  277. InsertHeadList(
  278. &AfdFreeGroupList,
  279. &newGroupTable[i].ListEntry
  280. );
  281. }
  282. AfdGroupTable = newGroupTable;
  283. AfdGroupTableSize = newGroupTableSize;
  284. }
  285. //
  286. // Pull the next free entry off the list.
  287. //
  288. ASSERT( !IsListEmpty( &AfdFreeGroupList ) );
  289. listEntry = RemoveHeadList( &AfdFreeGroupList );
  290. groupEntry = CONTAINING_RECORD(
  291. listEntry,
  292. AFD_GROUP_ENTRY,
  293. ListEntry
  294. );
  295. groupEntry->ReferenceCount = 1;
  296. groupEntry->GroupType = (AFD_GROUP_TYPE)groupValue;
  297. *Group = (LONG)( groupEntry - AfdGroupTable );
  298. *GroupType = groupEntry->GroupType;
  299. ExReleaseResourceLite( AfdGroupTableResource );
  300. KeLeaveCriticalRegion ();
  301. return TRUE;
  302. }
  303. //
  304. // Otherwise, just reference the group.
  305. //
  306. return AfdReferenceGroup( groupValue, GroupType );
  307. } // AfdGetGroup
  308. PAFD_GROUP_ENTRY
  309. AfdMapGroupToEntry(
  310. IN LONG Group
  311. )
  312. /*++
  313. Routine Description:
  314. Maps the given group ID to the corresponding AFD_GROUP_ENTRY structure.
  315. N.B. This routine returns with AfdGroupTableResource held if successful.
  316. Arguments:
  317. Group - The group ID to map.
  318. Return Value:
  319. PAFD_GROUP_ENTRY - The entry corresponding to the group ID if successful,
  320. NULL otherwise.
  321. --*/
  322. {
  323. PAFD_GROUP_ENTRY groupEntry;
  324. //
  325. // Lock the table.
  326. //
  327. //
  328. // Make sure the thread in which we execute cannot get
  329. // suspeneded in APC while we own the global resource.
  330. //
  331. KeEnterCriticalRegion ();
  332. ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
  333. //
  334. // Validate the group ID.
  335. //
  336. if( Group > 0 && Group < AfdGroupTableSize ) {
  337. groupEntry = AfdGroupTable + Group;
  338. //
  339. // The group ID is within legal range. Ensure it's in use.
  340. // In the AFD_GROUP_ENTRY structure, the GroupType field is
  341. // overlayed with ListEntry.Flink due to the internal union.
  342. // We can use this knowledge to quickly validate that this
  343. // entry is in use.
  344. //
  345. if( groupEntry->GroupType == GroupTypeConstrained ||
  346. groupEntry->GroupType == GroupTypeUnconstrained ) {
  347. return groupEntry;
  348. }
  349. }
  350. //
  351. // Invalid group ID, fail it.
  352. //
  353. ExReleaseResourceLite( AfdGroupTableResource );
  354. KeLeaveCriticalRegion ();
  355. return NULL;
  356. } // AfdMapGroupToEntry