Source code of Windows XP (NT5)
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.

708 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. buffer.c
  5. Abstract:
  6. The module implements a buffer in the style popularized by
  7. Michael J. Grier (MGrier), where some amount (like MAX_PATH)
  8. of storage is preallocated (like on the stack) and if the storage
  9. needs grow beyond the preallocated size, the heap is used.
  10. Author:
  11. Jay Krell (a-JayK) June 2000
  12. Environment:
  13. User Mode or Kernel Mode (but don't preallocate much on the stack in kernel mode)
  14. Revision History:
  15. --*/
  16. #include "ntos.h"
  17. #include "nt.h"
  18. #include "ntrtl.h"
  19. #include "nturtl.h"
  20. #include <limits.h>
  21. NTSTATUS
  22. NTAPI
  23. RtlpEnsureBufferSize(
  24. IN ULONG Flags,
  25. IN OUT PRTL_BUFFER Buffer,
  26. IN SIZE_T Size
  27. )
  28. /*++
  29. Routine Description:
  30. This function ensures Buffer can hold Size bytes, or returns
  31. an error. It either bumps Buffer->Size closer to Buffer->StaticSize,
  32. or heap allocates.
  33. Arguments:
  34. Buffer - a Buffer object, see also RtlInitBuffer.
  35. Size - the number of bytes the caller wishes to store in Buffer->Buffer.
  36. Return Value:
  37. STATUS_SUCCESS
  38. STATUS_NO_MEMORY
  39. --*/
  40. {
  41. NTSTATUS Status = STATUS_SUCCESS;
  42. PUCHAR Temp = NULL;
  43. if ((Flags & ~(RTL_ENSURE_BUFFER_SIZE_NO_COPY)) != 0) {
  44. Status = STATUS_INVALID_PARAMETER;
  45. goto Exit;
  46. }
  47. if (Buffer == NULL) {
  48. Status = STATUS_INVALID_PARAMETER;
  49. goto Exit;
  50. }
  51. if (Size <= Buffer->Size) {
  52. Status = STATUS_SUCCESS;
  53. goto Exit;
  54. }
  55. // Size <= Buffer->StaticSize does not imply static allocation, it
  56. // could be heap allocation that the client poked smaller.
  57. if (Buffer->Buffer == Buffer->StaticBuffer && Size <= Buffer->StaticSize) {
  58. Buffer->Size = Size;
  59. Status = STATUS_SUCCESS;
  60. goto Exit;
  61. }
  62. //
  63. // The realloc case was messed up in Whistler, and got removed.
  64. // Put it back in Blackcomb.
  65. //
  66. Temp = (PUCHAR)RtlAllocateStringRoutine(Size);
  67. if (Temp == NULL) {
  68. Status = STATUS_NO_MEMORY;
  69. goto Exit;
  70. }
  71. if ((Flags & RTL_ENSURE_BUFFER_SIZE_NO_COPY) == 0) {
  72. RtlCopyMemory(Temp, Buffer->Buffer, Buffer->Size);
  73. }
  74. if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buffer)) {
  75. RtlFreeStringRoutine(Buffer->Buffer);
  76. Buffer->Buffer = NULL;
  77. }
  78. ASSERT(Temp != NULL);
  79. Buffer->Buffer = Temp;
  80. Buffer->Size = Size;
  81. Status = STATUS_SUCCESS;
  82. Exit:
  83. return Status;
  84. }
  85. NTSTATUS
  86. NTAPI
  87. RtlMultiAppendUnicodeStringBuffer(
  88. OUT PRTL_UNICODE_STRING_BUFFER Destination,
  89. IN ULONG NumberOfSources,
  90. IN const UNICODE_STRING* SourceArray
  91. )
  92. /*++
  93. Routine Description:
  94. Arguments:
  95. Destination -
  96. NumberOfSources -
  97. SourceArray -
  98. Return Value:
  99. STATUS_SUCCESS
  100. STATUS_NO_MEMORY
  101. STATUS_NAME_TOO_LONG
  102. --*/
  103. {
  104. SIZE_T Length = 0;
  105. ULONG i = 0;
  106. NTSTATUS Status = STATUS_SUCCESS;
  107. const SIZE_T CharSize = sizeof(*Destination->String.Buffer);
  108. const ULONG OriginalDestinationLength = Destination->String.Length;
  109. Length = OriginalDestinationLength;
  110. for (i = 0 ; i != NumberOfSources ; ++i) {
  111. Length += SourceArray[i].Length;
  112. }
  113. Length += CharSize;
  114. if (Length > MAX_UNICODE_STRING_MAXLENGTH) {
  115. return STATUS_NAME_TOO_LONG;
  116. }
  117. Status = RtlEnsureBufferSize(0, &Destination->ByteBuffer, Length);
  118. if (!NT_SUCCESS(Status)) {
  119. return Status;
  120. }
  121. Destination->String.MaximumLength = (USHORT)Length;
  122. Destination->String.Length = (USHORT)(Length - CharSize);
  123. Destination->String.Buffer = (PWSTR)Destination->ByteBuffer.Buffer;
  124. Length = OriginalDestinationLength;
  125. for (i = 0 ; i != NumberOfSources ; ++i) {
  126. RtlMoveMemory(
  127. Destination->String.Buffer + Length / CharSize,
  128. SourceArray[i].Buffer,
  129. SourceArray[i].Length);
  130. Length += SourceArray[i].Length;
  131. }
  132. Destination->String.Buffer[Length / CharSize] = 0;
  133. return STATUS_SUCCESS;
  134. }
  135. #if 0 // not yet unused
  136. NTSTATUS
  137. NTAPI
  138. RtlPrependStringToUnicodeStringBuffer(
  139. IN ULONG Flags,
  140. IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer,
  141. IN PCUNICODE_STRING UnicodeString
  142. )
  143. /*++
  144. Routine Description:
  145. Insert a string at the beginning of a unicode string buffer.
  146. This should be equivalent to RtlInsertStringIntoUnicodeStringBuffer(0).
  147. Arguments:
  148. Flags - 0, room for future binary compatible expansion
  149. Buffer - buffer to change
  150. Length - number of chars to keep
  151. Return Value:
  152. STATUS_SUCCESS
  153. STATUS_INVALID_PARAMETER
  154. STATUS_NAME_TOO_LONG
  155. --*/
  156. {
  157. //
  158. // This could be sped up. It does an extra copy of the buffer's
  159. // existing contents when the buffer needs to grow.
  160. //
  161. NTSTATUS Status = STATUS_SUCCESS;
  162. if (Flags != 0) {
  163. Status = STATUS_INVALID_PARAMETER;
  164. goto Exit;
  165. }
  166. if (UnicodeStringBuffer == NULL) {
  167. Status = STATUS_INVALID_PARAMETER;
  168. goto Exit;
  169. }
  170. if (UnicodeString == NULL || UnicodeString->Length == 0) {
  171. Status = STATUS_SUCCESS;
  172. goto Exit;
  173. }
  174. Status =
  175. RtlEnsureUnicodeStringBufferSizeChars(
  176. UnicodeStringBuffer,
  177. RTL_STRING_GET_LENGTH_CHARS(&UnicodeStringBuffer->String)
  178. + RTL_STRING_GET_LENGTH_CHARS(UnicodeString)
  179. );
  180. if (!NT_SUCCESS(Status))
  181. goto Exit;
  182. RtlMoveMemory(
  183. UnicodeStringBuffer->String.Buffer + RTL_STRING_GET_LENGTH_CHARS(UnicodeString),
  184. UnicodeStringBuffer->String.Buffer,
  185. UnicodeStringBuffer->String.Length + sizeof(WCHAR)
  186. );
  187. RtlMoveMemory(
  188. UnicodeStringBuffer->String.Buffer
  189. UnicodeString->Buffer,
  190. UnicodeString->Length
  191. );
  192. UnicodeStringBuffer->String.Length += UnicodeString->Length;
  193. Status = STATUS_SUCCESS;
  194. Exit:
  195. return Status;
  196. }
  197. #endif
  198. #if 0 // not yet unused
  199. NTSTATUS
  200. NTAPI
  201. RtlUnicodeStringBufferRight(
  202. IN ULONG Flags,
  203. IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
  204. IN ULONG Length
  205. )
  206. /*++
  207. Routine Description:
  208. This function replaces a unicode string buffer with characters
  209. taken from its right. This requires a copy. In the future
  210. we should allow
  211. RTL_UNICODE_STRING_BUFFER.UnicodeString.Buffer
  212. != RTL_UNICODE_STRING_BUFFER.ByteBuffer.Buffer
  213. so this can be fast. Likewise for Mid.
  214. Arguments:
  215. Flags - 0, room for future binary compatible expansion
  216. Buffer - buffer to change
  217. Length - number of chars to keep
  218. Return Value:
  219. STATUS_SUCCESS
  220. STATUS_INVALID_PARAMETER
  221. --*/
  222. {
  223. NTSTATUS Status = STATUS_SUCCESS;
  224. const PUNICODE_STRING String = (Buffer == NULL ? NULL : &Buffer->String);
  225. const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
  226. if (Flags != 0) {
  227. Status = STATUS_INVALID_PARAMETER;
  228. goto Exit;
  229. }
  230. if (Buffer == NULL) {
  231. Status = STATUS_INVALID_PARAMETER;
  232. goto Exit;
  233. }
  234. if (Length >= CurrentLengthChars) {
  235. Status = STATUS_SUCCESS;
  236. goto Exit;
  237. }
  238. RtlMoveMemory(
  239. String->Buffer,
  240. String->Buffer + CurrentLengthChars - Length,
  241. Length * sizeof(String->Buffer[0])
  242. );
  243. RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, Length);
  244. RTL_STRING_NUL_TERMINATE(String);
  245. Status = STATUS_SUCCESS;
  246. Exit:
  247. return Status;
  248. }
  249. #endif
  250. #if 0 // not yet unused
  251. NTSTATUS
  252. NTAPI
  253. RtlUnicodeStringBufferLeft(
  254. IN ULONG Flags,
  255. IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
  256. IN ULONG Length
  257. )
  258. /*++
  259. Routine Description:
  260. This function replaces a unicode string buffer with characters
  261. taken from its left. This is fast.
  262. Arguments:
  263. Flags - 0, room for future binary compatible expansion
  264. Buffer - buffer to change
  265. Length - number of chars to keep
  266. Return Value:
  267. STATUS_SUCCESS
  268. STATUS_INVALID_PARAMETER
  269. --*/
  270. {
  271. NTSTATUS Status = STATUS_SUCCESS;
  272. const PUNICODE_STRING String = (Buffer == NULL ? NULL : &Buffer->String);
  273. const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
  274. if (Flags != 0) {
  275. Status = STATUS_INVALID_PARAMETER;
  276. goto Exit;
  277. }
  278. if (Buffer == NULL) {
  279. Status = STATUS_INVALID_PARAMETER;
  280. goto Exit;
  281. }
  282. if (Length >= CurrentLengthChars) {
  283. Status = STATUS_SUCCESS;
  284. goto Exit;
  285. }
  286. RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, Length);
  287. RTL_STRING_NUL_TERMINATE(String);
  288. Status = STATUS_SUCCESS;
  289. Exit:
  290. return Status;
  291. }
  292. #endif
  293. #if 0 // not yet unused
  294. NTSTATUS
  295. NTAPI
  296. RtlUnicodeStringBufferMid(
  297. IN ULONG Flags,
  298. IN OUT PRTL_UNICODE_STRING_BUFFER Buffer,
  299. IN ULONG Offset,
  300. IN ULONG Length
  301. )
  302. /*++
  303. Routine Description:
  304. This function replaces a unicode string buffer with characters
  305. taken from its "middle", as defined by an offset
  306. from the start and length, both in chars.
  307. Arguments:
  308. Flags - 0, room for future binary compatible expansion
  309. Buffer - buffer to change
  310. Offset - offset to keep chars from
  311. Length - number of chars to keep
  312. Return Value:
  313. STATUS_SUCCESS
  314. STATUS_INVALID_PARAMETER
  315. --*/
  316. {
  317. NTSTATUS Status = STATUS_SUCCESS;
  318. const PUNICODE_STRING String = (Buffer == NULL ? NULL : &Buffer->String);
  319. const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
  320. if (Flags != 0) {
  321. Status = STATUS_INVALID_PARAMETER;
  322. goto Exit;
  323. }
  324. if (Buffer == NULL) {
  325. Status = STATUS_INVALID_PARAMETER;
  326. goto Exit;
  327. }
  328. if (Offset >= CurrentLengthChars) {
  329. Offset = 0;
  330. Length = 0;
  331. } else if (Offset + Length >= CurrentLengthChars) {
  332. Length = CurrentLengthChars - Offset;
  333. }
  334. ASSERT(Offset < CurrentLengthChars);
  335. ASSERT(Length <= CurrentLengthChars);
  336. ASSERT(Offset + Length <= CurrentLengthChars);
  337. if (Length != 0 && Offset != 0 && Length != CurrentLengthChars) {
  338. RtlMoveMemory(
  339. String->Buffer,
  340. String->Buffer + Offset,
  341. Length * sizeof(String->Buffer[0])
  342. );
  343. }
  344. RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, Length);
  345. RTL_STRING_NUL_TERMINATE(String);
  346. Status = STATUS_SUCCESS;
  347. Exit:
  348. return Status;
  349. }
  350. #endif
  351. #if 0 // not yet unused
  352. NTSTATUS
  353. NTAPI
  354. RtlInsertStringIntoUnicodeStringBuffer(
  355. IN ULONG Flags,
  356. IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer,
  357. IN ULONG Offset,
  358. IN PCUNICODE_STRING InsertString
  359. )
  360. /*++
  361. Routine Description:
  362. This function insert a string into a unicode string buffer at
  363. a specified offset, growing the buffer as necessary to fit,
  364. and even handling the aliased case where the string and buffer overlap.
  365. Arguments:
  366. Flags - 0, the ever popular "room for future binary compatible expansion"
  367. UnicodeStringBuffer - buffer to insert string into
  368. Offset - offset to insert the string at
  369. InsertString - string to insert into UnicodeStringBuffer
  370. Return Value:
  371. STATUS_SUCCESS
  372. STATUS_INVALID_PARAMETER
  373. STATUS_NO_MEMORY
  374. STATUS_NAME_TOO_LONG
  375. --*/
  376. {
  377. NTSTATUS Status = STATUS_SUCCESS;
  378. typedef WCHAR TChar;
  379. const PUNICODE_STRING String = (UnicodeStringBuffer == NULL ? NULL : &UnicodeStringBuffer->String);
  380. const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
  381. const ULONG InsertStringLengthChars = (InsertString == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(InsertString));
  382. const ULONG NewLengthChars = CurrentLengthChars + InsertStringLengthChars;
  383. const ULONG NewLengthBytes = (CurrentLengthChars + InsertStringLengthChars) * sizeof(TChar);
  384. RTL_UNICODE_STRING_BUFFER AliasBuffer = { 0 };
  385. BOOLEAN Alias = FALSE;
  386. ULONG i = 0;
  387. if (Flags != 0) {
  388. Status = STATUS_INVALID_PARAMETER;
  389. goto Exit;
  390. }
  391. if (UnicodeStringBuffer == NULL) {
  392. Status = STATUS_INVALID_PARAMETER;
  393. goto Exit;
  394. }
  395. if (InsertString == NULL || InsertString->Length == 0) {
  396. Status = STATUS_SUCCESS;
  397. goto Exit;
  398. }
  399. if (Offset >= CurrentLengthChars) {
  400. Offset = CurrentLengthChars;
  401. }
  402. //
  403. // Check for aliasing. This check is overly cautious.
  404. //
  405. if (InsertString->Buffer >= String->Buffer && InsertString->Buffer < String->Buffer + CurrentLengthChars) {
  406. Alias = TRUE;
  407. }
  408. else if (String->Buffer >= InsertString->Buffer && String->Buffer < InsertString->Buffer + InsertStringLengthChars) {
  409. Alias = TRUE;
  410. }
  411. if (Alias) {
  412. RtlInitUnicodeStringBuffer(&AliasBuffer, NULL, 0);
  413. Status = RtlAssignUnicodeStringBuffer(&AliasBuffer, InsertString);
  414. if (!NT_SUCCESS(Status))
  415. goto Exit;
  416. InsertString = &AliasBuffer->String;
  417. }
  418. Status = RtlEnsureUnicodeBufferSizeChars(UnicodeStringBuffer, NewLength);
  419. if (!NT_SUCCESS(Status))
  420. goto Exit;
  421. RtlMoveMemory(String->Buffer + Offset + InsertStringLengthChars, String->Buffer + Offset, (CurrentLengthChars - Offset) * sizeof(TChar));
  422. RtlMoveMemory(String->Buffer + Offset, InsertString->Insert, InsertStringLengthChars * sizeof(TChar));
  423. RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, NewLength);
  424. RTL_STRING_NUL_TERMINATE(String);
  425. Status = STATUS_SUCCESS;
  426. Exit:
  427. RtlFreeUnicodeStringBuffer(&AliasBuffer);
  428. return Status;
  429. }
  430. #endif
  431. #if 0 // not yet unused
  432. NTSTATUS
  433. NTAPI
  434. RtlBufferTakeValue(
  435. IN ULONG Flags,
  436. IN OUT PRTL_BUFFER DestinationBuffer,
  437. IN OUT PRTL_BUFFER SourceBuffer
  438. )
  439. /*++
  440. Routine Description:
  441. This function copies the value of one RTL_BUFFER to another
  442. and frees the source, in one step. If source is heap allocated, this enables
  443. the optimization of not doing a RtlMoveMemory, just moving the pointers and sizes.
  444. Arguments:
  445. Flags - 0
  446. DestinationBuffer - ends up holding source's value
  447. SourceBuffer - ends up freed
  448. Return Value:
  449. STATUS_SUCCESS
  450. STATUS_INVALID_PARAMETER
  451. STATUS_NO_MEMORY
  452. --*/
  453. {
  454. NTSTATUS Status = STATUS_SUCCESS;
  455. typedef WCHAR TChar;
  456. if (Flags != 0) {
  457. Status = STATUS_INVALID_PARAMETER;
  458. goto Exit;
  459. }
  460. if (DestinationBuffer == NULL) {
  461. Status = STATUS_INVALID_PARAMETER;
  462. goto Exit;
  463. }
  464. if (SourceBuffer == NULL) {
  465. RtlFreeBuffer(DestinationBuffer);
  466. Status = STATUS_SUCCESS;
  467. goto Exit;
  468. }
  469. if (RTLP_BUFFER_IS_HEAP_ALLOCATED(SourceBuffer)
  470. && SourceBuffer->ReservedForIMalloc == DestinationBuffer->ReservedForIMalloc
  471. ) {
  472. DestinationBuffer->Size = SourceBuffer->Size;
  473. DestinationBuffer->Buffer = SourceBuffer->Buffer;
  474. SourceBuffer->Buffer = SourceBuffer->StaticBuffer;
  475. SourceBuffer->Size = SourceBuffer->StaticSize;
  476. goto Exit;
  477. }
  478. Status = RtlEnsureBufferSize(RTL_ENSURE_BUFFER_SIZE_NO_COPY, DestinationBuffer, SourceBuffer->Size);
  479. if (!NT_SUCCESS(Status))
  480. goto Exit;
  481. RtlMoveMemory(DestinationBuffer->Buffer, SourceBuffer->Buffer, SourceBuffer->Size);
  482. RtlFreeBuffer(SourceBuffer);
  483. Status = STATUS_SUCCESS;
  484. Exit:
  485. return Status;
  486. }
  487. #endif
  488. #if 0 // not yet unused
  489. NTSTATUS
  490. NTAPI
  491. RtlValidateBuffer(
  492. IN ULONG Flags,
  493. IN CONST RTL_BUFFER* Buffer
  494. )
  495. /*++
  496. Routine Description:
  497. This function performs some sanity checking on the buffer.
  498. Arguments:
  499. Flags - 0
  500. Buffer - the buffer to check
  501. Return Value:
  502. STATUS_SUCCESS - the buffer is aok
  503. STATUS_INVALID_PARAMETER - the buffer is not good
  504. --*/
  505. {
  506. NTSTATUS Status = STATUS_SUCCESS;
  507. if (Flags != 0) {
  508. Status = STATUS_INVALID_PARAMETER
  509. goto Exit;
  510. }
  511. if (Buffer == NULL) {
  512. Status = STATUS_SUCCESS;
  513. goto Exit;
  514. }
  515. Status = STATUS_INVALID_PARAMETER;
  516. if (!RTL_IMPLIES(Buffer->Buffer == Buffer->StaticBuffer, Buffer->Size <= Buffer->StaticSize))
  517. goto Exit;
  518. Status = STATUS_SUCCESS;
  519. Exit:
  520. return Status;
  521. }
  522. #endif
  523. #if 0 // not yet unused
  524. NTSTATUS
  525. NTAPI
  526. RtlValidateUnicodeStringBuffer(
  527. IN ULONG Flags,
  528. IN CONST RTL_UNICODE_STRING_BUFFER* UnicodeStringBuffer
  529. )
  530. /*++
  531. Routine Description:
  532. This function performs some sanity checking on the buffer.
  533. Arguments:
  534. Flags - 0
  535. UnicodeStringBuffer - the buffer to check
  536. Return Value:
  537. STATUS_SUCCESS - the buffer is aok
  538. STATUS_INVALID_PARAMETER - the buffer is not good
  539. --*/
  540. {
  541. NTSTATUS Status = STATUS_SUCCESS;
  542. if (Flags != 0) {
  543. Status = STATUS_INVALID_PARAMETER;
  544. goto Exit;
  545. }
  546. if (UnicodeStringBuffer == NULL) {
  547. Status = STATUS_SUCCESS;
  548. goto Exit;
  549. }
  550. if (!RTL_VERIFY(NT_SUCCESS(Status = RtlValidateUnicodeString(&UnicodeStringBuffer->String))))
  551. goto Exit;
  552. if (!RTL_VERIFY(NT_SUCCESS(Status = RtlValidateBuffer(&UnicodeStringBuffer->Buffer))))
  553. goto Exit;
  554. Status = STATUS_INVALID_PARAMETER;
  555. if (!RTL_VERIFY(UnicodeStringBuffer->String.Length < UnicodeStringBuffer->ByteBuffer.Size))
  556. goto Exit;
  557. if (!RTL_VERIFY(UnicodeStringBuffer->String.MaximumLength >= UnicodeStringBuffer->String.Length))
  558. goto Exit;
  559. if (!RTL_VERIFY(UnicodeStringBuffer->String.MaximumLength == UnicodeStringBuffer->ByteBuffer.Size))
  560. goto Exit;
  561. if (!RTL_VERIFY(UnicodeStringBuffer->String.Buffer == UnicodeStringBuffer->ByteBuffer.Buffer))
  562. goto Exit;
  563. if (!RTL_VERIFY(UnicodeStringBuffer->String.MaximumLength != 0))
  564. goto Exit;
  565. Status = STATUS_SUCCESS;
  566. Exit:
  567. return Status;
  568. }
  569. #endif
  570. #if 0
  571. static void test()
  572. {
  573. RTL_BUFFER Buffer = { 0 };
  574. UCHAR chars[260 * sizeof(WCHAR)];
  575. RtlInitBuffer(&Buffer, chars, sizeof(chars));
  576. RtlEnsureBufferSize(0, &Buffer, 1024 * sizeof(WCHAR));
  577. RtlFreeBuffer(&Buffer);
  578. }
  579. #endif