|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
buffer.c
Abstract:
The module implements a buffer in the style popularized by Michael J. Grier (MGrier), where some amount (like MAX_PATH) of storage is preallocated (like on the stack) and if the storage needs grow beyond the preallocated size, the heap is used.
Author:
Jay Krell (a-JayK) June 2000
Environment:
User Mode or Kernel Mode (but don't preallocate much on the stack in kernel mode)
Revision History:
--*/ #include "ntos.h"
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include <limits.h>
NTSTATUS NTAPI RtlpEnsureBufferSize( IN ULONG Flags, IN OUT PRTL_BUFFER Buffer, IN SIZE_T Size ) /*++
Routine Description:
This function ensures Buffer can hold Size bytes, or returns an error. It either bumps Buffer->Size closer to Buffer->StaticSize, or heap allocates.
Arguments:
Buffer - a Buffer object, see also RtlInitBuffer.
Size - the number of bytes the caller wishes to store in Buffer->Buffer.
Return Value:
STATUS_SUCCESS STATUS_NO_MEMORY
--*/ { NTSTATUS Status = STATUS_SUCCESS; PUCHAR Temp = NULL;
if ((Flags & ~(RTL_ENSURE_BUFFER_SIZE_NO_COPY)) != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
if (Size <= Buffer->Size) { Status = STATUS_SUCCESS; goto Exit; } // Size <= Buffer->StaticSize does not imply static allocation, it
// could be heap allocation that the client poked smaller.
if (Buffer->Buffer == Buffer->StaticBuffer && Size <= Buffer->StaticSize) { Buffer->Size = Size; Status = STATUS_SUCCESS; goto Exit; } //
// The realloc case was messed up in Whistler, and got removed.
// Put it back in Blackcomb.
//
Temp = (PUCHAR)RtlAllocateStringRoutine(Size); if (Temp == NULL) { Status = STATUS_NO_MEMORY; goto Exit; }
if ((Flags & RTL_ENSURE_BUFFER_SIZE_NO_COPY) == 0) { RtlCopyMemory(Temp, Buffer->Buffer, Buffer->Size); }
if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buffer)) { RtlFreeStringRoutine(Buffer->Buffer); Buffer->Buffer = NULL; } ASSERT(Temp != NULL); Buffer->Buffer = Temp; Buffer->Size = Size; Status = STATUS_SUCCESS; Exit: return Status; }
NTSTATUS NTAPI RtlMultiAppendUnicodeStringBuffer( OUT PRTL_UNICODE_STRING_BUFFER Destination, IN ULONG NumberOfSources, IN const UNICODE_STRING* SourceArray ) /*++
Routine Description:
Arguments:
Destination - NumberOfSources - SourceArray -
Return Value:
STATUS_SUCCESS STATUS_NO_MEMORY STATUS_NAME_TOO_LONG
--*/ { SIZE_T Length = 0; ULONG i = 0; NTSTATUS Status = STATUS_SUCCESS; const SIZE_T CharSize = sizeof(*Destination->String.Buffer); const ULONG OriginalDestinationLength = Destination->String.Length;
Length = OriginalDestinationLength; for (i = 0 ; i != NumberOfSources ; ++i) { Length += SourceArray[i].Length; } Length += CharSize; if (Length > MAX_UNICODE_STRING_MAXLENGTH) { return STATUS_NAME_TOO_LONG; }
Status = RtlEnsureBufferSize(0, &Destination->ByteBuffer, Length); if (!NT_SUCCESS(Status)) { return Status; } Destination->String.MaximumLength = (USHORT)Length; Destination->String.Length = (USHORT)(Length - CharSize); Destination->String.Buffer = (PWSTR)Destination->ByteBuffer.Buffer; Length = OriginalDestinationLength; for (i = 0 ; i != NumberOfSources ; ++i) { RtlMoveMemory( Destination->String.Buffer + Length / CharSize, SourceArray[i].Buffer, SourceArray[i].Length); Length += SourceArray[i].Length; } Destination->String.Buffer[Length / CharSize] = 0; return STATUS_SUCCESS; }
#if 0 // not yet unused
NTSTATUS NTAPI RtlPrependStringToUnicodeStringBuffer( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer, IN PCUNICODE_STRING UnicodeString ) /*++
Routine Description:
Insert a string at the beginning of a unicode string buffer. This should be equivalent to RtlInsertStringIntoUnicodeStringBuffer(0).
Arguments:
Flags - 0, room for future binary compatible expansion Buffer - buffer to change Length - number of chars to keep
Return Value:
STATUS_SUCCESS STATUS_INVALID_PARAMETER STATUS_NAME_TOO_LONG --*/ { //
// This could be sped up. It does an extra copy of the buffer's
// existing contents when the buffer needs to grow.
//
NTSTATUS Status = STATUS_SUCCESS;
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (UnicodeStringBuffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (UnicodeString == NULL || UnicodeString->Length == 0) { Status = STATUS_SUCCESS; goto Exit; } Status = RtlEnsureUnicodeStringBufferSizeChars( UnicodeStringBuffer, RTL_STRING_GET_LENGTH_CHARS(&UnicodeStringBuffer->String) + RTL_STRING_GET_LENGTH_CHARS(UnicodeString) ); if (!NT_SUCCESS(Status)) goto Exit;
RtlMoveMemory( UnicodeStringBuffer->String.Buffer + RTL_STRING_GET_LENGTH_CHARS(UnicodeString), UnicodeStringBuffer->String.Buffer, UnicodeStringBuffer->String.Length + sizeof(WCHAR) ); RtlMoveMemory( UnicodeStringBuffer->String.Buffer UnicodeString->Buffer, UnicodeString->Length ); UnicodeStringBuffer->String.Length += UnicodeString->Length;
Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlUnicodeStringBufferRight( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, IN ULONG Length ) /*++
Routine Description:
This function replaces a unicode string buffer with characters taken from its right. This requires a copy. In the future we should allow RTL_UNICODE_STRING_BUFFER.UnicodeString.Buffer != RTL_UNICODE_STRING_BUFFER.ByteBuffer.Buffer so this can be fast. Likewise for Mid.
Arguments:
Flags - 0, room for future binary compatible expansion Buffer - buffer to change Length - number of chars to keep
Return Value:
STATUS_SUCCESS STATUS_INVALID_PARAMETER --*/ { NTSTATUS Status = STATUS_SUCCESS; const PUNICODE_STRING String = (Buffer == NULL ? NULL : &Buffer->String); const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Length >= CurrentLengthChars) { Status = STATUS_SUCCESS; goto Exit; }
RtlMoveMemory( String->Buffer, String->Buffer + CurrentLengthChars - Length, Length * sizeof(String->Buffer[0]) );
RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, Length); RTL_STRING_NUL_TERMINATE(String); Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlUnicodeStringBufferLeft( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, IN ULONG Length ) /*++
Routine Description:
This function replaces a unicode string buffer with characters taken from its left. This is fast.
Arguments:
Flags - 0, room for future binary compatible expansion Buffer - buffer to change Length - number of chars to keep
Return Value:
STATUS_SUCCESS STATUS_INVALID_PARAMETER --*/ { NTSTATUS Status = STATUS_SUCCESS; const PUNICODE_STRING String = (Buffer == NULL ? NULL : &Buffer->String); const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Length >= CurrentLengthChars) { Status = STATUS_SUCCESS; goto Exit; }
RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, Length); RTL_STRING_NUL_TERMINATE(String); Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlUnicodeStringBufferMid( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, IN ULONG Offset, IN ULONG Length ) /*++
Routine Description:
This function replaces a unicode string buffer with characters taken from its "middle", as defined by an offset from the start and length, both in chars.
Arguments:
Flags - 0, room for future binary compatible expansion Buffer - buffer to change Offset - offset to keep chars from Length - number of chars to keep
Return Value:
STATUS_SUCCESS STATUS_INVALID_PARAMETER --*/ { NTSTATUS Status = STATUS_SUCCESS; const PUNICODE_STRING String = (Buffer == NULL ? NULL : &Buffer->String); const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String));
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; }
if (Offset >= CurrentLengthChars) { Offset = 0; Length = 0; } else if (Offset + Length >= CurrentLengthChars) { Length = CurrentLengthChars - Offset; } ASSERT(Offset < CurrentLengthChars); ASSERT(Length <= CurrentLengthChars); ASSERT(Offset + Length <= CurrentLengthChars); if (Length != 0 && Offset != 0 && Length != CurrentLengthChars) { RtlMoveMemory( String->Buffer, String->Buffer + Offset, Length * sizeof(String->Buffer[0]) ); } RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, Length); RTL_STRING_NUL_TERMINATE(String); Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlInsertStringIntoUnicodeStringBuffer( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer, IN ULONG Offset, IN PCUNICODE_STRING InsertString ) /*++
Routine Description:
This function insert a string into a unicode string buffer at a specified offset, growing the buffer as necessary to fit, and even handling the aliased case where the string and buffer overlap.
Arguments:
Flags - 0, the ever popular "room for future binary compatible expansion" UnicodeStringBuffer - buffer to insert string into Offset - offset to insert the string at InsertString - string to insert into UnicodeStringBuffer
Return Value:
STATUS_SUCCESS STATUS_INVALID_PARAMETER STATUS_NO_MEMORY STATUS_NAME_TOO_LONG --*/ { NTSTATUS Status = STATUS_SUCCESS; typedef WCHAR TChar; const PUNICODE_STRING String = (UnicodeStringBuffer == NULL ? NULL : &UnicodeStringBuffer->String); const ULONG CurrentLengthChars = (String == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(String)); const ULONG InsertStringLengthChars = (InsertString == NULL ? 0 : RTL_STRING_GET_LENGTH_CHARS(InsertString)); const ULONG NewLengthChars = CurrentLengthChars + InsertStringLengthChars; const ULONG NewLengthBytes = (CurrentLengthChars + InsertStringLengthChars) * sizeof(TChar); RTL_UNICODE_STRING_BUFFER AliasBuffer = { 0 }; BOOLEAN Alias = FALSE; ULONG i = 0;
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (UnicodeStringBuffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (InsertString == NULL || InsertString->Length == 0) { Status = STATUS_SUCCESS; goto Exit; } if (Offset >= CurrentLengthChars) { Offset = CurrentLengthChars; }
//
// Check for aliasing. This check is overly cautious.
//
if (InsertString->Buffer >= String->Buffer && InsertString->Buffer < String->Buffer + CurrentLengthChars) { Alias = TRUE; } else if (String->Buffer >= InsertString->Buffer && String->Buffer < InsertString->Buffer + InsertStringLengthChars) { Alias = TRUE; } if (Alias) { RtlInitUnicodeStringBuffer(&AliasBuffer, NULL, 0); Status = RtlAssignUnicodeStringBuffer(&AliasBuffer, InsertString); if (!NT_SUCCESS(Status)) goto Exit; InsertString = &AliasBuffer->String; }
Status = RtlEnsureUnicodeBufferSizeChars(UnicodeStringBuffer, NewLength); if (!NT_SUCCESS(Status)) goto Exit; RtlMoveMemory(String->Buffer + Offset + InsertStringLengthChars, String->Buffer + Offset, (CurrentLengthChars - Offset) * sizeof(TChar)); RtlMoveMemory(String->Buffer + Offset, InsertString->Insert, InsertStringLengthChars * sizeof(TChar)); RTL_STRING_SET_LENGTH_CHARS_UNSAFE(String, NewLength); RTL_STRING_NUL_TERMINATE(String); Status = STATUS_SUCCESS; Exit: RtlFreeUnicodeStringBuffer(&AliasBuffer); return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlBufferTakeValue( IN ULONG Flags, IN OUT PRTL_BUFFER DestinationBuffer, IN OUT PRTL_BUFFER SourceBuffer ) /*++
Routine Description:
This function copies the value of one RTL_BUFFER to another and frees the source, in one step. If source is heap allocated, this enables the optimization of not doing a RtlMoveMemory, just moving the pointers and sizes.
Arguments:
Flags - 0 DestinationBuffer - ends up holding source's value SourceBuffer - ends up freed
Return Value:
STATUS_SUCCESS STATUS_INVALID_PARAMETER STATUS_NO_MEMORY --*/ { NTSTATUS Status = STATUS_SUCCESS; typedef WCHAR TChar;
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (DestinationBuffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (SourceBuffer == NULL) { RtlFreeBuffer(DestinationBuffer); Status = STATUS_SUCCESS; goto Exit; }
if (RTLP_BUFFER_IS_HEAP_ALLOCATED(SourceBuffer) && SourceBuffer->ReservedForIMalloc == DestinationBuffer->ReservedForIMalloc ) { DestinationBuffer->Size = SourceBuffer->Size; DestinationBuffer->Buffer = SourceBuffer->Buffer; SourceBuffer->Buffer = SourceBuffer->StaticBuffer; SourceBuffer->Size = SourceBuffer->StaticSize; goto Exit; } Status = RtlEnsureBufferSize(RTL_ENSURE_BUFFER_SIZE_NO_COPY, DestinationBuffer, SourceBuffer->Size); if (!NT_SUCCESS(Status)) goto Exit; RtlMoveMemory(DestinationBuffer->Buffer, SourceBuffer->Buffer, SourceBuffer->Size); RtlFreeBuffer(SourceBuffer);
Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlValidateBuffer( IN ULONG Flags, IN CONST RTL_BUFFER* Buffer ) /*++
Routine Description:
This function performs some sanity checking on the buffer.
Arguments:
Flags - 0 Buffer - the buffer to check
Return Value:
STATUS_SUCCESS - the buffer is aok STATUS_INVALID_PARAMETER - the buffer is not good --*/ { NTSTATUS Status = STATUS_SUCCESS;
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER goto Exit; } if (Buffer == NULL) { Status = STATUS_SUCCESS; goto Exit; } Status = STATUS_INVALID_PARAMETER; if (!RTL_IMPLIES(Buffer->Buffer == Buffer->StaticBuffer, Buffer->Size <= Buffer->StaticSize)) goto Exit;
Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0 // not yet unused
NTSTATUS NTAPI RtlValidateUnicodeStringBuffer( IN ULONG Flags, IN CONST RTL_UNICODE_STRING_BUFFER* UnicodeStringBuffer ) /*++
Routine Description:
This function performs some sanity checking on the buffer.
Arguments:
Flags - 0 UnicodeStringBuffer - the buffer to check
Return Value:
STATUS_SUCCESS - the buffer is aok STATUS_INVALID_PARAMETER - the buffer is not good --*/ { NTSTATUS Status = STATUS_SUCCESS;
if (Flags != 0) { Status = STATUS_INVALID_PARAMETER; goto Exit; } if (UnicodeStringBuffer == NULL) { Status = STATUS_SUCCESS; goto Exit; } if (!RTL_VERIFY(NT_SUCCESS(Status = RtlValidateUnicodeString(&UnicodeStringBuffer->String)))) goto Exit; if (!RTL_VERIFY(NT_SUCCESS(Status = RtlValidateBuffer(&UnicodeStringBuffer->Buffer)))) goto Exit; Status = STATUS_INVALID_PARAMETER; if (!RTL_VERIFY(UnicodeStringBuffer->String.Length < UnicodeStringBuffer->ByteBuffer.Size)) goto Exit; if (!RTL_VERIFY(UnicodeStringBuffer->String.MaximumLength >= UnicodeStringBuffer->String.Length)) goto Exit; if (!RTL_VERIFY(UnicodeStringBuffer->String.MaximumLength == UnicodeStringBuffer->ByteBuffer.Size)) goto Exit; if (!RTL_VERIFY(UnicodeStringBuffer->String.Buffer == UnicodeStringBuffer->ByteBuffer.Buffer)) goto Exit; if (!RTL_VERIFY(UnicodeStringBuffer->String.MaximumLength != 0)) goto Exit;
Status = STATUS_SUCCESS; Exit: return Status; }
#endif
#if 0
static void test() { RTL_BUFFER Buffer = { 0 }; UCHAR chars[260 * sizeof(WCHAR)];
RtlInitBuffer(&Buffer, chars, sizeof(chars)); RtlEnsureBufferSize(0, &Buffer, 1024 * sizeof(WCHAR)); RtlFreeBuffer(&Buffer); } #endif
|