Windows NT 4.0 source code leak
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.

537 lines
10 KiB

4 years ago
  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(
  70. NonPagedPool,
  71. sizeof(*AfdGroupTableResource),
  72. AFD_RESOURCE_POOL_TAG
  73. );
  74. if( AfdGroupTableResource == NULL ) {
  75. return FALSE;
  76. }
  77. ExInitializeResourceLite( AfdGroupTableResource );
  78. AfdGroupTable = NULL;
  79. InitializeListHead( &AfdFreeGroupList );
  80. AfdGroupTableSize = 0;
  81. return TRUE;
  82. } // AfdInitializeGroup
  83. VOID
  84. AfdTerminateGroup(
  85. VOID
  86. )
  87. /*++
  88. Routine Description:
  89. Destroys any globals created for the group ID package.
  90. --*/
  91. {
  92. if( AfdGroupTableResource != NULL ) {
  93. ExDeleteResourceLite( AfdGroupTableResource );
  94. AFD_FREE_POOL(
  95. AfdGroupTableResource,
  96. AFD_RESOURCE_POOL_TAG
  97. );
  98. AfdGroupTableResource = NULL;
  99. }
  100. if( AfdGroupTable != NULL ) {
  101. AFD_FREE_POOL(
  102. AfdGroupTable,
  103. AFD_GROUP_POOL_TAG
  104. );
  105. AfdGroupTable = NULL;
  106. }
  107. InitializeListHead( &AfdFreeGroupList );
  108. AfdGroupTableSize = 0;
  109. } // AfdTerminateGroup
  110. BOOLEAN
  111. AfdReferenceGroup(
  112. IN LONG Group,
  113. OUT PAFD_GROUP_TYPE GroupType
  114. )
  115. /*++
  116. Routine Description:
  117. Bumps the reference count associated with the given group ID.
  118. Arguments:
  119. Group - The group ID to reference.
  120. GroupType - Returns the type of the group.
  121. Returns:
  122. BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
  123. --*/
  124. {
  125. PAFD_GROUP_ENTRY groupEntry;
  126. AFD_GROUP_TYPE groupType;
  127. groupEntry = AfdMapGroupToEntry( Group );
  128. if( groupEntry != NULL ) {
  129. groupType = groupEntry->GroupType;
  130. if( groupType == GroupTypeConstrained ||
  131. groupType == GroupTypeUnconstrained ) {
  132. groupEntry->ReferenceCount++;
  133. *GroupType = groupType;
  134. } else {
  135. groupEntry = NULL;
  136. }
  137. ExReleaseResourceLite( AfdGroupTableResource );
  138. }
  139. return (BOOLEAN)( groupEntry != NULL );
  140. } // AfdReferenceGroup
  141. BOOLEAN
  142. AfdDereferenceGroup(
  143. IN LONG Group
  144. )
  145. /*++
  146. Routine Description:
  147. Decrements the reference count associated with the given group ID.
  148. If the ref count drops to zero, the group ID is freed.
  149. Arguments:
  150. Group - The group ID to dereference.
  151. Returns:
  152. BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
  153. --*/
  154. {
  155. PAFD_GROUP_ENTRY groupEntry;
  156. AFD_GROUP_TYPE groupType;
  157. groupEntry = AfdMapGroupToEntry( Group );
  158. if( groupEntry != NULL ) {
  159. groupType = groupEntry->GroupType;
  160. if( groupType == GroupTypeConstrained ||
  161. groupType == GroupTypeUnconstrained ) {
  162. ASSERT( groupEntry->ReferenceCount > 0 );
  163. groupEntry->ReferenceCount--;
  164. if( groupEntry->ReferenceCount == 0 ) {
  165. InsertTailList(
  166. &AfdFreeGroupList,
  167. &groupEntry->ListEntry
  168. );
  169. }
  170. } else {
  171. groupEntry = NULL;
  172. }
  173. ExReleaseResourceLite( AfdGroupTableResource );
  174. }
  175. return (BOOLEAN)( groupEntry != NULL );
  176. } // AfdDereferenceGroup
  177. BOOLEAN
  178. AfdGetGroup(
  179. IN OUT PLONG Group,
  180. OUT PAFD_GROUP_TYPE GroupType
  181. )
  182. /*++
  183. Routine Description:
  184. Examines the incoming group. If is zero, then nothing is done. If it
  185. is SG_CONSTRAINED_GROUP, then a new constrained group ID is created.
  186. If it is SG_UNCONSTRAINED_GROUP, then a new unconstrained group ID is
  187. created. Otherwise, it must identify an existing group, so that group
  188. is referenced.
  189. Arguments:
  190. Group - Points to the group ID to examine/modify.
  191. GroupType - Returns the type of the group.
  192. Return Value:
  193. BOOLEAN - TRUE if successful, FALSE otherwise.
  194. --*/
  195. {
  196. LONG groupValue;
  197. PAFD_GROUP_ENTRY groupEntry;
  198. PAFD_GROUP_ENTRY newGroupTable;
  199. LONG newGroupTableSize;
  200. LONG i;
  201. PLIST_ENTRY listEntry;
  202. groupValue = *Group;
  203. //
  204. // Zero means "no group", so just ignore it.
  205. //
  206. if( groupValue == 0 ) {
  207. *GroupType = GroupTypeNeither;
  208. return TRUE;
  209. }
  210. //
  211. // If we're being asked to create a new group, do it.
  212. //
  213. if( groupValue == SG_CONSTRAINED_GROUP ||
  214. groupValue == SG_UNCONSTRAINED_GROUP ) {
  215. //
  216. // Lock the table.
  217. //
  218. ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
  219. //
  220. // See if there's room at the inn.
  221. //
  222. if( IsListEmpty( &AfdFreeGroupList ) ) {
  223. //
  224. // No room, we'll need to create/expand the table.
  225. //
  226. newGroupTableSize = AfdGroupTableSize + AFD_GROUP_TABLE_GROWTH;
  227. newGroupTable = AFD_ALLOCATE_POOL(
  228. PagedPool,
  229. newGroupTableSize * sizeof(AFD_GROUP_ENTRY),
  230. AFD_GROUP_POOL_TAG
  231. );
  232. if( newGroupTable == NULL ) {
  233. ExReleaseResourceLite( AfdGroupTableResource );
  234. return FALSE;
  235. }
  236. if( AfdGroupTable == NULL ) {
  237. //
  238. // This is the initial table allocation, so reserve the
  239. // first three entries (0, SG_UNCONSTRAINED_GROUP, and
  240. // SG_CONSTRAINED_GROUP).
  241. //
  242. for( ;
  243. AfdGroupTableSize <= SG_CONSTRAINED_GROUP ||
  244. AfdGroupTableSize <= SG_UNCONSTRAINED_GROUP ;
  245. AfdGroupTableSize++ ) {
  246. newGroupTable[AfdGroupTableSize].ReferenceCount = 0;
  247. newGroupTable[AfdGroupTableSize].GroupType = GroupTypeNeither;
  248. }
  249. } else {
  250. //
  251. // Copy the old table into the new table, then free the
  252. // old table.
  253. //
  254. RtlCopyMemory(
  255. newGroupTable,
  256. AfdGroupTable,
  257. AfdGroupTableSize * sizeof(AFD_GROUP_ENTRY)
  258. );
  259. AFD_FREE_POOL(
  260. AfdGroupTable,
  261. AFD_GROUP_POOL_TAG
  262. );
  263. }
  264. //
  265. // Add the new entries to the free list.
  266. //
  267. for( i = newGroupTableSize - 1 ; i >= AfdGroupTableSize ; i-- ) {
  268. InsertHeadList(
  269. &AfdFreeGroupList,
  270. &newGroupTable[i].ListEntry
  271. );
  272. }
  273. AfdGroupTable = newGroupTable;
  274. AfdGroupTableSize = newGroupTableSize;
  275. }
  276. //
  277. // Pull the next free entry off the list.
  278. //
  279. ASSERT( !IsListEmpty( &AfdFreeGroupList ) );
  280. listEntry = RemoveHeadList( &AfdFreeGroupList );
  281. groupEntry = CONTAINING_RECORD(
  282. listEntry,
  283. AFD_GROUP_ENTRY,
  284. ListEntry
  285. );
  286. groupEntry->ReferenceCount = 1;
  287. groupEntry->GroupType = (AFD_GROUP_TYPE)groupValue;
  288. *Group = ( groupEntry - AfdGroupTable );
  289. *GroupType = groupEntry->GroupType;
  290. ExReleaseResourceLite( AfdGroupTableResource );
  291. return TRUE;
  292. }
  293. //
  294. // Otherwise, just reference the group.
  295. //
  296. return AfdReferenceGroup( groupValue, GroupType );
  297. } // AfdGetGroup
  298. PAFD_GROUP_ENTRY
  299. AfdMapGroupToEntry(
  300. IN LONG Group
  301. )
  302. /*++
  303. Routine Description:
  304. Maps the given group ID to the corresponding AFD_GROUP_ENTRY structure.
  305. N.B. This routine returns with AfdGroupTableResource held if successful.
  306. Arguments:
  307. Group - The group ID to map.
  308. Return Value:
  309. PAFD_GROUP_ENTRY - The entry corresponding to the group ID if successful,
  310. NULL otherwise.
  311. --*/
  312. {
  313. PAFD_GROUP_ENTRY groupEntry;
  314. //
  315. // Lock the table.
  316. //
  317. ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
  318. //
  319. // Validate the group ID.
  320. //
  321. if( Group > 0 && Group < AfdGroupTableSize ) {
  322. groupEntry = AfdGroupTable + Group;
  323. //
  324. // The group ID is within legal range. Ensure it's in use.
  325. // In the AFD_GROUP_ENTRY structure, the GroupType field is
  326. // overlayed with ListEntry.Flink due to the internal union.
  327. // We can use this knowledge to quickly validate that this
  328. // entry is in use.
  329. //
  330. if( groupEntry->GroupType == GroupTypeConstrained ||
  331. groupEntry->GroupType == GroupTypeUnconstrained ) {
  332. return groupEntry;
  333. }
  334. }
  335. //
  336. // Invalid group ID, fail it.
  337. //
  338. ExReleaseResourceLite( AfdGroupTableResource );
  339. return NULL;
  340. } // AfdMapGroupToEntry