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.

330 lines
8.5 KiB

  1. // from base\ntdll\buffer.c
  2. // belongs in base\ntos\rtl\buffer.c
  3. /*++
  4. Copyright (c) Microsoft Corporation
  5. Module Name:
  6. buffer.c
  7. Abstract:
  8. The module implements a buffer in the style popularized by
  9. Michael J. Grier (MGrier), where some amount (like MAX_PATH)
  10. of storage is preallocated (like on the stack) and if the storage
  11. needs grow beyond the preallocated size, the heap is used.
  12. Author:
  13. Jay Krell (a-JayK) June 2000
  14. Environment:
  15. User Mode or Kernel Mode (but don't preallocate much on the stack in kernel mode)
  16. Revision History:
  17. --*/
  18. #include "spprecmp.h"
  19. #pragma warning(disable:4214) // bit field types other than int
  20. #pragma warning(disable:4201) // nameless struct/union
  21. #pragma warning(disable:4115) // named type definition in parentheses
  22. #pragma warning(disable:4127) // condition expression is constant
  23. #define _NTOS_ /* prevent #including ntos.h, only use functions exported from ntdll/ntoskrnl
  24. for usermode/kernelmode portability */
  25. #include "nt.h"
  26. #include "ntrtl.h"
  27. #include "nturtl.h"
  28. #include <limits.h>
  29. #include "ntrtlstringandbuffer.h"
  30. NTSTATUS
  31. NTAPI
  32. RtlpEnsureBufferSize (
  33. IN ULONG Flags,
  34. IN OUT PRTL_BUFFER Buffer,
  35. IN SIZE_T Size
  36. )
  37. /*++
  38. Routine Description:
  39. This function ensures Buffer can hold Size bytes, or returns
  40. an error. It either bumps Buffer->Size closer to Buffer->StaticSize,
  41. or heap allocates.
  42. Arguments:
  43. Buffer - a Buffer object, see also RtlInitBuffer.
  44. Size - the number of bytes the caller wishes to store in Buffer->Buffer.
  45. Return Value:
  46. STATUS_SUCCESS
  47. STATUS_NO_MEMORY
  48. --*/
  49. {
  50. PUCHAR Temp;
  51. if ((Flags & ~(RTL_ENSURE_BUFFER_SIZE_NO_COPY)) != 0) {
  52. return STATUS_INVALID_PARAMETER;
  53. }
  54. if (Buffer == NULL) {
  55. return STATUS_INVALID_PARAMETER;
  56. }
  57. if (Size <= Buffer->Size) {
  58. return STATUS_SUCCESS;
  59. }
  60. // Size <= Buffer->StaticSize does not imply static allocation, it
  61. // could be heap allocation that the client poked smaller.
  62. if (Buffer->Buffer == Buffer->StaticBuffer && Size <= Buffer->StaticSize) {
  63. Buffer->Size = Size;
  64. return STATUS_SUCCESS;
  65. }
  66. //
  67. // The realloc case was messed up in Whistler, and got removed.
  68. // Put it back in Blackcomb.
  69. //
  70. Temp = (PUCHAR)RtlAllocateStringRoutine(Size);
  71. if (Temp == NULL) {
  72. return STATUS_NO_MEMORY;
  73. }
  74. if ((Flags & RTL_ENSURE_BUFFER_SIZE_NO_COPY) == 0) {
  75. RtlCopyMemory(Temp, Buffer->Buffer, Buffer->Size);
  76. }
  77. if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buffer)) {
  78. RtlFreeStringRoutine(Buffer->Buffer);
  79. Buffer->Buffer = NULL;
  80. }
  81. ASSERT(Temp != NULL);
  82. Buffer->Buffer = Temp;
  83. Buffer->Size = Size;
  84. return STATUS_SUCCESS;
  85. }
  86. NTSTATUS
  87. NTAPI
  88. RtlMultiAppendUnicodeStringBuffer (
  89. OUT PRTL_UNICODE_STRING_BUFFER Destination,
  90. IN ULONG NumberOfSources,
  91. IN const UNICODE_STRING* SourceArray
  92. )
  93. /*++
  94. Routine Description:
  95. Arguments:
  96. Destination -
  97. NumberOfSources -
  98. SourceArray -
  99. Return Value:
  100. STATUS_SUCCESS
  101. STATUS_NO_MEMORY
  102. STATUS_NAME_TOO_LONG
  103. --*/
  104. {
  105. SIZE_T Length;
  106. ULONG i;
  107. NTSTATUS Status;
  108. const SIZE_T CharSize = sizeof(*Destination->String.Buffer);
  109. const ULONG OriginalDestinationLength = Destination->String.Length;
  110. Length = OriginalDestinationLength;
  111. for (i = 0 ; i != NumberOfSources ; ++i) {
  112. Length += SourceArray[i].Length;
  113. if (Length > MAX_UNICODE_STRING_MAXLENGTH) {
  114. return STATUS_NAME_TOO_LONG;
  115. }
  116. }
  117. Length += CharSize;
  118. if (Length > MAX_UNICODE_STRING_MAXLENGTH) {
  119. return STATUS_NAME_TOO_LONG;
  120. }
  121. Status = RtlEnsureBufferSize(0, &Destination->ByteBuffer, Length);
  122. if (!NT_SUCCESS(Status)) {
  123. return Status;
  124. }
  125. Destination->String.MaximumLength = (USHORT)Length;
  126. Destination->String.Length = (USHORT)(Length - CharSize);
  127. Destination->String.Buffer = (PWSTR)Destination->ByteBuffer.Buffer;
  128. Length = OriginalDestinationLength;
  129. for (i = 0 ; i != NumberOfSources ; ++i) {
  130. RtlMoveMemory(
  131. Destination->String.Buffer + Length / CharSize,
  132. SourceArray[i].Buffer,
  133. SourceArray[i].Length);
  134. Length += SourceArray[i].Length;
  135. }
  136. Destination->String.Buffer[Length / CharSize] = 0;
  137. return STATUS_SUCCESS;
  138. }
  139. NTSTATUS
  140. NTAPI
  141. RtlInitAnsiStringBuffer(
  142. PRTL_ANSI_STRING_BUFFER StringBuffer,
  143. PUCHAR StaticBuffer,
  144. SIZE_T StaticSize
  145. )
  146. {
  147. PANSI_STRING String;
  148. NTSTATUS NtStatus = STATUS_INTERNAL_ERROR;
  149. if (!RTL_SOFT_VERIFY(StringBuffer != NULL)) {
  150. NtStatus = STATUS_INVALID_PARAMETER;
  151. goto Exit;
  152. }
  153. if (StaticSize < sizeof(StringBuffer)->MinimumStaticBufferForTerminalNul
  154. || StaticBuffer == NULL) {
  155. StaticSize = sizeof(StringBuffer->MinimumStaticBufferForTerminalNul);
  156. StaticBuffer = StringBuffer->MinimumStaticBufferForTerminalNul;
  157. }
  158. if (StaticSize > MAX_UNICODE_STRING_MAXLENGTH) {
  159. StaticSize = MAX_UNICODE_STRING_MAXLENGTH;
  160. }
  161. RtlInitBuffer(&StringBuffer->ByteBuffer, StaticBuffer, StaticSize);
  162. String = &StringBuffer->String;
  163. String->Length = 0;
  164. String->MaximumLength = (RTL_STRING_LENGTH_TYPE)StaticSize;
  165. String->Buffer = StaticBuffer;
  166. StaticBuffer[0] = 0;
  167. NtStatus = STATUS_SUCCESS;
  168. Exit:
  169. return NtStatus;
  170. }
  171. VOID
  172. NTAPI
  173. RtlFreeAnsiStringBuffer(
  174. PRTL_ANSI_STRING_BUFFER StringBuffer
  175. )
  176. {
  177. if (StringBuffer != NULL) {
  178. const PRTL_BUFFER ByteBuffer = &StringBuffer->ByteBuffer;
  179. RtlFreeBuffer(ByteBuffer);
  180. //
  181. // ok for reuse or repeat free
  182. //
  183. RtlInitAnsiStringBuffer(StringBuffer, ByteBuffer->StaticBuffer, ByteBuffer->StaticSize);
  184. }
  185. }
  186. NTSTATUS
  187. NTAPI
  188. RtlAssignAnsiStringBufferFromUnicodeString(
  189. PRTL_ANSI_STRING_BUFFER StringBuffer,
  190. PCUNICODE_STRING UnicodeString
  191. )
  192. {
  193. PANSI_STRING String;
  194. PRTL_BUFFER ByteBuffer;
  195. NTSTATUS NtStatus = STATUS_INTERNAL_ERROR;
  196. if (!RTL_SOFT_VERIFY(StringBuffer != NULL)) {
  197. NtStatus = STATUS_INVALID_PARAMETER;
  198. goto Exit;
  199. }
  200. if (!RTL_SOFT_VERIFY(UnicodeString != NULL)) {
  201. NtStatus = STATUS_INVALID_PARAMETER;
  202. goto Exit;
  203. }
  204. ByteBuffer = &StringBuffer->ByteBuffer;
  205. NtStatus =
  206. RtlEnsureBufferSize(
  207. RTL_ENSURE_BUFFER_SIZE_NO_COPY,
  208. ByteBuffer,
  209. (RTL_STRING_GET_LENGTH_CHARS(UnicodeString) * 2) + 1);
  210. if (!NT_SUCCESS(NtStatus)) {
  211. goto Exit;
  212. }
  213. String = &StringBuffer->String;
  214. String->Length = 0;
  215. String->MaximumLength = (RTL_STRING_LENGTH_TYPE)ByteBuffer->Size;
  216. String->Buffer = (PSTR)ByteBuffer->Buffer;
  217. NtStatus = RtlUnicodeStringToAnsiString(String, UnicodeString, FALSE);
  218. if (!NT_SUCCESS(NtStatus)) {
  219. goto Exit;
  220. }
  221. RTL_STRING_NUL_TERMINATE(String);
  222. NtStatus = STATUS_SUCCESS;
  223. Exit:
  224. return NtStatus;
  225. }
  226. NTSTATUS
  227. NTAPI
  228. RtlAssignAnsiStringBufferFromUnicode(
  229. PRTL_ANSI_STRING_BUFFER StringBuffer,
  230. PCWSTR Unicode
  231. )
  232. {
  233. UNICODE_STRING UnicodeString;
  234. NTSTATUS NtStatus;
  235. NtStatus = RtlInitUnicodeStringEx(&UnicodeString, Unicode);
  236. if (!NT_SUCCESS(NtStatus)) {
  237. goto Exit;
  238. }
  239. NtStatus = RtlAssignAnsiStringBufferFromUnicodeString(StringBuffer, &UnicodeString);
  240. if (!NT_SUCCESS(NtStatus)) {
  241. goto Exit;
  242. }
  243. NtStatus = STATUS_SUCCESS;
  244. Exit:
  245. return NtStatus;
  246. }
  247. NTSTATUS
  248. NTAPI
  249. RtlUnicodeStringBufferEnsureTrailingNtPathSeperator(
  250. PRTL_UNICODE_STRING_BUFFER StringBuffer
  251. )
  252. {
  253. PUNICODE_STRING String = NULL;
  254. NTSTATUS NtStatus = STATUS_INTERNAL_ERROR;
  255. const WCHAR SeperatorChar = L'\\';
  256. const static UNICODE_STRING SeperatorString = RTL_CONSTANT_STRING(L"\\");
  257. if (!RTL_SOFT_VERIFY(StringBuffer != NULL)) {
  258. NtStatus = STATUS_INVALID_PARAMETER;
  259. goto Exit;
  260. }
  261. String = &StringBuffer->String;
  262. if (String->Length == 0 || RTL_STRING_GET_LAST_CHAR(String) != SeperatorChar) {
  263. NtStatus = RtlAppendUnicodeStringBuffer(StringBuffer, &SeperatorString);
  264. if (!NT_SUCCESS(NtStatus)) {
  265. goto Exit;
  266. }
  267. }
  268. NtStatus = STATUS_SUCCESS;
  269. Exit:
  270. return NtStatus;
  271. }