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.

456 lines
9.0 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. stack.c
  5. Abstract:
  6. This provides a generic stack handler to push/pop things onto it
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. User, Kernel
  11. --*/
  12. #include "pch.h"
  13. NTSTATUS
  14. StackAllocate(
  15. OUT PSTACK *Stack,
  16. IN ULONG StackElementSize
  17. )
  18. /*++
  19. Routine Description:
  20. This routine allocates memory and returns a stack object
  21. Arguments:
  22. Stack - Where to store a pointer to the stack
  23. StackElementSize - How much space on the stack a single element takes
  24. up
  25. Return Value:
  26. NTSTATUS
  27. --*/
  28. {
  29. PSTACK tempStack;
  30. NTSTATUS status = STATUS_SUCCESS;
  31. //
  32. // Make sure that we have some place to store the stack pointer
  33. //
  34. ASSERT( Stack != NULL );
  35. ASSERT( StackElementSize != 0 );
  36. //
  37. // Allocate a block of memory for the stack
  38. //
  39. tempStack = MEMORY_ALLOCATE(
  40. sizeof(STACK) + ( (STACK_GROWTH_RATE * StackElementSize) - 1)
  41. );
  42. if (tempStack == NULL) {
  43. status = STATUS_INSUFFICIENT_RESOURCES;
  44. goto StackAllocateExit;
  45. }
  46. //
  47. // Setup the control block of the stack
  48. //
  49. tempStack->Signature = (ULONG) STACK_SIGNATURE;
  50. tempStack->StackSize = STACK_GROWTH_RATE * StackElementSize;
  51. tempStack->StackElementSize = StackElementSize;
  52. tempStack->TopOfStack = 0;
  53. //
  54. // Zero out the current elements on the stack
  55. //
  56. MEMORY_ZERO(
  57. &(tempStack->Stack[0]),
  58. STACK_GROWTH_RATE * StackElementSize
  59. );
  60. //
  61. // Return the stack pointer
  62. //
  63. StackAllocateExit:
  64. *Stack = tempStack;
  65. return status;
  66. }
  67. NTSTATUS
  68. StackFree(
  69. IN OUT PSTACK *Stack
  70. )
  71. /*++
  72. Routine Description:
  73. This routine frees the stack
  74. Arguments:
  75. Stack - Where to find a pointer to the stack
  76. Return Value:
  77. NTSTATUS
  78. --*/
  79. {
  80. //
  81. // Make sure that we point to something
  82. //
  83. ASSERT( Stack != NULL );
  84. ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
  85. //
  86. // Free the stack
  87. //
  88. MEMORY_FREE( *Stack );
  89. //
  90. // Point the stack to nowhere
  91. //
  92. *Stack = NULL;
  93. return STATUS_SUCCESS;
  94. }
  95. NTSTATUS
  96. StackParent(
  97. IN OUT PSTACK *Stack,
  98. IN PVOID Child,
  99. OUT PVOID Parent
  100. )
  101. /*++
  102. Routine Description:
  103. This routine returns a pointer to the stack location that is before
  104. the given Child.
  105. Arguments:
  106. Stack - The stack to operate on
  107. Child - This is the node whose parent we want
  108. Parent - This is where we store a pointer to the parent stack loc
  109. Return Value:
  110. NTSTATUS
  111. --*/
  112. {
  113. PSTACK localStack;
  114. ULONG Addr = (ULONG) Child;
  115. //
  116. // Make sure that we point to something
  117. //
  118. ASSERT( Stack != NULL );
  119. ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
  120. ASSERT( Parent != NULL );
  121. //
  122. // make sure that the child node actually lies on the stack
  123. //
  124. localStack = *Stack;
  125. if ( Addr < (ULONG) localStack->Stack ||
  126. Addr > (ULONG) &(localStack->Stack[localStack->TopOfStack + 1]) -
  127. localStack->StackElementSize ) {
  128. *( (PULONG *)Parent) = NULL;
  129. return STATUS_FAIL_CHECK;
  130. }
  131. //
  132. // Make sure that the child node isn't the first element
  133. //
  134. if (Addr < (ULONG) &(localStack->Stack[localStack->StackElementSize]) ) {
  135. *( (PULONG *)Parent) = NULL;
  136. return STATUS_SUCCESS;
  137. }
  138. //
  139. // Set the parent to be one before the child
  140. //
  141. *( (PULONG *)Parent) = (PULONG) (Addr - localStack->StackElementSize);
  142. //
  143. // Done
  144. //
  145. return STATUS_SUCCESS;
  146. }
  147. NTSTATUS
  148. StackPop(
  149. IN OUT PSTACK *Stack
  150. )
  151. /*++
  152. Routine Description:
  153. This routine reclaims the memory used for a stack location
  154. and wipes out whatever data existed in the reclaimed area
  155. Arguments:
  156. Stack - Where to find a pointer to the stack
  157. Return Value:
  158. NTSTATUS
  159. --*/
  160. {
  161. PSTACK localStack;
  162. //
  163. // Make sure that we point to something
  164. //
  165. ASSERT( Stack != NULL );
  166. ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
  167. //
  168. // Is there an item that we can remove from the stack?
  169. //
  170. localStack = *Stack;
  171. if ( localStack->TopOfStack == 0) {
  172. return STATUS_FAIL_CHECK;
  173. }
  174. //
  175. // Wipe out the top-most element on the stack
  176. //
  177. localStack->TopOfStack -= localStack->StackElementSize;
  178. MEMORY_ZERO(
  179. &( localStack->Stack[ localStack->TopOfStack ] ),
  180. localStack->StackElementSize
  181. );
  182. return STATUS_SUCCESS;
  183. }
  184. NTSTATUS
  185. StackPush(
  186. IN OUT PSTACK *Stack,
  187. OUT PVOID StackElement
  188. )
  189. /*++
  190. Routine Description:
  191. This routine obtains a pointer for an object on the top of the stack
  192. and increments the top to point to something that can be then be used
  193. again.
  194. Arguments:
  195. Stack - Where to find a pointer to the stack
  196. StackElement - Pointer to the element to be added to the stack
  197. Return Value:
  198. NTSTATUS
  199. --*/
  200. {
  201. PSTACK localStack;
  202. PSTACK tempStack;
  203. ULONG newSize;
  204. ULONG deltaSize;
  205. //
  206. // Make sure that we point to something
  207. //
  208. ASSERT( Stack != NULL );
  209. ASSERT( StackElement != NULL );
  210. //
  211. // Find the stack pointer and make sure that the signature is still
  212. // valid
  213. //
  214. localStack = *Stack;
  215. ASSERT( localStack->Signature == STACK_SIGNATURE );
  216. //
  217. // Do we have enough space on the stack?
  218. //
  219. if ( localStack->TopOfStack >= localStack->StackSize ) {
  220. //
  221. // Figure out how many bytes by which to grow the stack and how
  222. // large the total stack should be
  223. //
  224. deltaSize = (STACK_GROWTH_RATE * localStack->StackElementSize);
  225. newSize = sizeof(STACK) + localStack->StackSize + deltaSize - 1;
  226. //
  227. // Grow the stack
  228. //
  229. tempStack = MEMORY_ALLOCATE( newSize );
  230. if (tempStack == NULL) {
  231. return STATUS_INSUFFICIENT_RESOURCES;
  232. }
  233. //
  234. // Empty the new stack and copy the old one to it
  235. //
  236. MEMORY_ZERO( &(tempStack->Stack[0]), newSize - sizeof(STACK) + 1);
  237. MEMORY_COPY( tempStack, localStack , newSize - deltaSize);
  238. //
  239. // Make sure that the new stack has the correct size
  240. //
  241. tempStack->StackSize += deltaSize;
  242. //
  243. // Free the old stack
  244. //
  245. StackFree( Stack );
  246. //
  247. // Set the stack to point to the new one
  248. //
  249. *Stack = localStack = tempStack;
  250. }
  251. //
  252. // Grab a pointer to the part that we will return to the caller
  253. //
  254. *( (PUCHAR *)StackElement) = &(localStack->Stack[ localStack->TopOfStack ]);
  255. //
  256. // Find the new Top of Stack
  257. //
  258. localStack->TopOfStack += localStack->StackElementSize;
  259. //
  260. // Done
  261. //
  262. return STATUS_SUCCESS;
  263. }
  264. NTSTATUS
  265. StackRoot(
  266. IN OUT PSTACK *Stack,
  267. OUT PVOID RootElement
  268. )
  269. /*++
  270. Routine Description:
  271. This routine returns the first element on the stack
  272. Arguments:
  273. Stack - Where the stack is located
  274. RootElement - Where to store the pointer to the root stack element
  275. Return Value:
  276. NTSTATUS
  277. --*/
  278. {
  279. PSTACK localStack;
  280. ASSERT( Stack != NULL && *Stack != NULL );
  281. ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
  282. localStack = *Stack;
  283. if (localStack->TopOfStack < localStack->StackElementSize) {
  284. //
  285. // There is no stack location we can use
  286. //
  287. *( (PUCHAR *)RootElement) = NULL;
  288. return STATUS_UNSUCCESSFUL;
  289. }
  290. //
  291. // Grab the root element
  292. //
  293. *( (PUCHAR *)RootElement) = localStack->Stack;
  294. //
  295. // Done
  296. //
  297. return STATUS_SUCCESS;
  298. }
  299. NTSTATUS
  300. StackTop(
  301. IN OUT PSTACK *Stack,
  302. OUT PVOID TopElement
  303. )
  304. /*++
  305. Routine Description:
  306. This routine returns the topmost stack location that is in current use
  307. Arguments:
  308. Stack - Where the stack is located
  309. TopElement - Where to store the pointer to the top stack element
  310. Return Value:
  311. NTSTATUS
  312. --*/
  313. {
  314. PSTACK localStack;
  315. ULONG offset;
  316. ASSERT( Stack != NULL );
  317. ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
  318. localStack = *Stack;
  319. if (localStack->TopOfStack < localStack->StackElementSize) {
  320. //
  321. // No stack locations are in current use
  322. //
  323. *( (PUCHAR *)TopElement) = NULL;
  324. return STATUS_UNSUCCESSFUL;
  325. } else {
  326. offset = localStack->TopOfStack - localStack->StackElementSize;
  327. }
  328. //
  329. // Grab the top stack location
  330. //
  331. *( (PUCHAR *)TopElement) = &(localStack->Stack[ offset ]);
  332. //
  333. // Done
  334. //
  335. return STATUS_SUCCESS;
  336. }