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.

408 lines
9.8 KiB

  1. #include "nt.h"
  2. #include "ntdef.h"
  3. #include "ntrtl.h"
  4. #include "nturtl.h"
  5. #include "generichandles.h"
  6. NTSTATUS
  7. RtlpGenericTableAddSlots(
  8. PGENERIC_HANDLE_TABLE pCreatedTable,
  9. PGENERIC_HANDLE_SLOT pSlots,
  10. USHORT usSlots
  11. )
  12. {
  13. NTSTATUS status = STATUS_SUCCESS;
  14. USHORT us;
  15. ASSERT(pCreatedTable != NULL);
  16. ASSERT(pSlots != NULL);
  17. ASSERT(usSlots > 0);
  18. RtlZeroMemory(pSlots, sizeof(GENERIC_HANDLE_SLOT) * usSlots);
  19. //
  20. // Next, next, next
  21. //
  22. for (us = 0; us < (usSlots - 1); us++) {
  23. pSlots[us].pNextFree = pSlots + (us + 1);
  24. }
  25. //
  26. // If there were no free slots, set this run as the new list of free
  27. // slots. Otherwise, set this as the "next available" free slot
  28. //
  29. if (pCreatedTable->pFirstFreeSlot != NULL) {
  30. pCreatedTable->pFirstFreeSlot->pNextFree = pSlots;
  31. }
  32. //
  33. // Add these to the list of slots
  34. //
  35. pCreatedTable->usSlotCount += usSlots;
  36. //
  37. // If there was no set of slots on the table already, then add these as the
  38. // current list of slots
  39. //
  40. if (pCreatedTable->pSlots == NULL) {
  41. pCreatedTable->pSlots = pSlots;
  42. }
  43. pCreatedTable->pFirstFreeSlot = pSlots;
  44. return status;
  45. }
  46. NTSTATUS
  47. RtlCreateGenericHandleTable(
  48. ULONG ulFlags,
  49. PGENERIC_HANDLE_TABLE pCreatedTable,
  50. PFNHANDLETABLEALLOC pfnAlloc,
  51. PFNHANDLETABLEFREE pfnFree,
  52. SIZE_T ulcbOriginalBlob,
  53. PVOID pvOriginalBlob
  54. )
  55. {
  56. NTSTATUS status = STATUS_SUCCESS;
  57. if ((ulFlags != 0) || (pCreatedTable == NULL) || (ulcbOriginalBlob && !pvOriginalBlob)) {
  58. return STATUS_INVALID_PARAMETER;
  59. }
  60. RtlZeroMemory(pCreatedTable, sizeof(*pCreatedTable));
  61. pCreatedTable->pfnAlloc = pfnAlloc;
  62. pCreatedTable->pfnFree = pfnFree;
  63. pCreatedTable->ulFlags = ulFlags;
  64. pCreatedTable->usInlineHandleSlots = (USHORT)(ulcbOriginalBlob / sizeof(GENERIC_HANDLE_SLOT));
  65. //
  66. // If there were slots handed to us, then initialize the table to use those first
  67. //
  68. if (pCreatedTable->usInlineHandleSlots > 0) {
  69. pCreatedTable->pInlineHandleSlots = (PGENERIC_HANDLE_SLOT)pvOriginalBlob;
  70. //
  71. // Now, add the slots that we were handed into the free list
  72. //
  73. status = RtlpGenericTableAddSlots(
  74. pCreatedTable,
  75. pCreatedTable->pSlots,
  76. pCreatedTable->usInlineHandleSlots);
  77. }
  78. //
  79. // Otherwise, everything is zero-initted already, so just bop out
  80. //
  81. return status;
  82. }
  83. NTSTATUS
  84. RtlCreateGenericHandleTableInPlace(
  85. ULONG ulFlags,
  86. SIZE_T cbInPlace,
  87. PVOID pvPlace,
  88. PFNHANDLETABLEALLOC pfnAlloc,
  89. PFNHANDLETABLEFREE pfnFree,
  90. PGENERIC_HANDLE_TABLE *ppCreatedTable
  91. )
  92. {
  93. NTSTATUS status;
  94. if ((pvPlace == NULL) || (cbInPlace && !pvPlace) || !ppCreatedTable) {
  95. return STATUS_INVALID_PARAMETER;
  96. }
  97. else if (cbInPlace < sizeof(GENERIC_HANDLE_TABLE)) {
  98. return STATUS_BUFFER_TOO_SMALL;
  99. }
  100. *ppCreatedTable = (PGENERIC_HANDLE_TABLE)pvPlace;
  101. status = RtlCreateGenericHandleTable(
  102. ulFlags,
  103. *ppCreatedTable,
  104. pfnAlloc,
  105. pfnFree,
  106. cbInPlace - sizeof(GENERIC_HANDLE_TABLE),
  107. *ppCreatedTable + 1);
  108. return status;
  109. }
  110. #define HANDLE_TABLE_SLOT_MASK (0x0000FFFF)
  111. #define HANDLE_TABLE_GEN_FLAG_SHIFT (16)
  112. #define HANDLE_TABLE_IN_USE_FLAG (0x8000)
  113. #define HANDLE_TABLE_GENERATION_MASK (~HANDLE_TABLE_IN_USE_FLAG)
  114. NTSTATUS
  115. RtlpFindSlotForHandle(
  116. PGENERIC_HANDLE_TABLE pHandleTable,
  117. PVOID pvHandle,
  118. PGENERIC_HANDLE_SLOT *ppSlot
  119. )
  120. {
  121. PGENERIC_HANDLE_SLOT pSlot;
  122. USHORT usSlotEntry = (USHORT)((ULONG_PTR)pvHandle & HANDLE_TABLE_SLOT_MASK);
  123. USHORT usGeneration = (USHORT)((ULONG_PTR)pvHandle >> HANDLE_TABLE_GEN_FLAG_SHIFT);
  124. pSlot = pHandleTable->pSlots + usSlotEntry;
  125. //
  126. // Generation flag not in use, gen mismatch, or not in the table? Oops.
  127. //
  128. if (((usGeneration & HANDLE_TABLE_IN_USE_FLAG) == 0) ||
  129. (usSlotEntry >= pHandleTable->usSlotCount) ||
  130. (pSlot->usGenerationFlag != usGeneration)) {
  131. return STATUS_NOT_FOUND;
  132. }
  133. //
  134. // Return that the slot was found
  135. //
  136. else {
  137. *ppSlot = pSlot;
  138. return STATUS_SUCCESS;
  139. }
  140. }
  141. NTSTATUS
  142. RtlAddRefGenericHandle(
  143. PGENERIC_HANDLE_TABLE pHandleTable,
  144. PVOID pvGenericHandle
  145. )
  146. {
  147. PGENERIC_HANDLE_SLOT pSlot;
  148. NTSTATUS status;
  149. if (pHandleTable == NULL) {
  150. return STATUS_INVALID_PARAMETER;
  151. }
  152. status = RtlpFindSlotForHandle(pHandleTable, pvGenericHandle, &pSlot);
  153. if (!NT_SUCCESS(status)) {
  154. return status;
  155. }
  156. pSlot->ulRefCount++;
  157. return STATUS_SUCCESS;
  158. }
  159. NTSTATUS
  160. RtlReleaseGenericHandle(
  161. PGENERIC_HANDLE_TABLE pHandleTable,
  162. PVOID pvGenericHandle
  163. )
  164. {
  165. PGENERIC_HANDLE_SLOT pSlot;
  166. NTSTATUS status;
  167. if (pHandleTable == NULL) {
  168. return STATUS_INVALID_PARAMETER;
  169. }
  170. status = RtlpFindSlotForHandle(pHandleTable, pvGenericHandle, &pSlot);
  171. if (!NT_SUCCESS(status)) {
  172. return status;
  173. }
  174. pSlot->ulRefCount--;
  175. return STATUS_SUCCESS;
  176. }
  177. NTSTATUS
  178. RtlRemoveGenericHandle(
  179. PGENERIC_HANDLE_TABLE pHandleTable,
  180. ULONG ulFlags,
  181. PVOID pvObjectHandle
  182. )
  183. {
  184. PGENERIC_HANDLE_SLOT pSlot = NULL;
  185. NTSTATUS status;
  186. if ((pHandleTable == NULL) || (ulFlags != 0)) {
  187. return STATUS_INVALID_PARAMETER;
  188. }
  189. status = RtlpFindSlotForHandle(pHandleTable, pvObjectHandle, &pSlot);
  190. if (!NT_SUCCESS(status)) {
  191. return status;
  192. }
  193. //
  194. // Flip the in-use flag
  195. //
  196. pSlot->usGenerationFlag &= ~HANDLE_TABLE_IN_USE_FLAG;
  197. pSlot->pNextFree = pHandleTable->pFirstFreeSlot;
  198. pHandleTable->pFirstFreeSlot = pSlot;
  199. return STATUS_SUCCESS;
  200. }
  201. NTSTATUS
  202. RtlDereferenceHandle(
  203. PGENERIC_HANDLE_TABLE pHandleTable,
  204. PVOID pvGenericHandle,
  205. PVOID *ppvObjectPointer
  206. )
  207. {
  208. USHORT usSlotEntry;
  209. NTSTATUS status;
  210. PGENERIC_HANDLE_SLOT pSlot = NULL;
  211. if ((pHandleTable == NULL) || (pvGenericHandle == NULL) || (ppvObjectPointer == NULL)) {
  212. return STATUS_INVALID_PARAMETER;
  213. }
  214. *ppvObjectPointer = NULL;
  215. status = RtlpFindSlotForHandle(pHandleTable, pvGenericHandle, &pSlot);
  216. if (!NT_SUCCESS(status)) {
  217. return status;
  218. }
  219. *ppvObjectPointer = pSlot->pvThisHandle;
  220. return STATUS_SUCCESS;
  221. }
  222. NTSTATUS
  223. RtlpExpandGenericHandleTable(
  224. PGENERIC_HANDLE_TABLE pHandleTable,
  225. ULONG ulNewSlotCount
  226. )
  227. {
  228. PGENERIC_HANDLE_SLOT pNewSlots = NULL;
  229. NTSTATUS status;
  230. //
  231. // New slot count is 0? Make it 20 instead.
  232. //
  233. if (ulNewSlotCount == 0) {
  234. ulNewSlotCount = pHandleTable->usSlotCount + 20;
  235. }
  236. //
  237. // Did we fly out of range?
  238. //
  239. if (ulNewSlotCount > 0xFFFF) {
  240. ulNewSlotCount = 0xFFFF;
  241. //
  242. // Can't allocate more, the table is full
  243. //
  244. if (ulNewSlotCount == pHandleTable->usSlotCount) {
  245. return STATUS_NO_MEMORY;
  246. }
  247. }
  248. //
  249. // Don't ever do this if there are free slots left in the table
  250. //
  251. ASSERT(pHandleTable->pFirstFreeSlot == NULL);
  252. status = pHandleTable->pfnAlloc(sizeof(GENERIC_HANDLE_SLOT) * ulNewSlotCount, (PVOID*)&pNewSlots);
  253. if (!NT_SUCCESS(status)) {
  254. return status;
  255. }
  256. return status;
  257. }
  258. NTSTATUS
  259. RtlAddGenericHandle(
  260. PGENERIC_HANDLE_TABLE pHandleTable,
  261. ULONG ulFlags,
  262. PVOID pvObject,
  263. PVOID *ppvObjectHandle
  264. )
  265. {
  266. PGENERIC_HANDLE_SLOT pSlot = NULL;
  267. NTSTATUS status;
  268. if (ppvObjectHandle)
  269. *ppvObjectHandle = NULL;
  270. if ((pHandleTable == NULL) || (ulFlags != 0) || (pvObject != NULL) || (ppvObjectHandle == NULL)) {
  271. return STATUS_INVALID_PARAMETER;
  272. }
  273. if (pHandleTable->pFirstFreeSlot == NULL) {
  274. status = RtlpExpandGenericHandleTable(pHandleTable, (pHandleTable->usSlotCount * 3) / 2);
  275. if (!NT_SUCCESS(status)) {
  276. return status;
  277. }
  278. }
  279. ASSERT(pHandleTable->pFirstFreeSlot != NULL);
  280. //
  281. // Adjust free list
  282. //
  283. pSlot = pHandleTable->pFirstFreeSlot;
  284. pHandleTable->pFirstFreeSlot = pSlot->pNextFree;
  285. //
  286. // Set up the various flags.
  287. //
  288. ASSERT((pSlot->usGenerationFlag & HANDLE_TABLE_IN_USE_FLAG) == 0);
  289. //
  290. // Increment the generation flag, set the in-use flag
  291. //
  292. pSlot->usGenerationFlag = (pSlot->usGenerationFlag & HANDLE_TABLE_GENERATION_MASK) + 1;
  293. pSlot->usGenerationFlag |= HANDLE_TABLE_IN_USE_FLAG;
  294. pSlot->ulRefCount = 0;
  295. //
  296. // Record the object pointer
  297. //
  298. pSlot->pvThisHandle = pvObject;
  299. //
  300. // The object handle is composed of 16 bits of generation mask plus the top-bit set
  301. // (which nicely avoids people casting it to a pointer that they can use), and
  302. // the lower 16 bits of "slot number", or an index into the handle table.
  303. //
  304. *ppvObjectHandle = (PVOID)((ULONG_PTR)(
  305. (pSlot->usGenerationFlag << HANDLE_TABLE_GEN_FLAG_SHIFT) |
  306. ((pSlot - pHandleTable->pInlineHandleSlots) & HANDLE_TABLE_SLOT_MASK)));
  307. return STATUS_SUCCESS;
  308. }