|
|
#include "nt.h"
#include "ntdef.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "ntrtl.h"
#include "sxs-rtl.h"
#include "skiplist.h"
#include "stringpool.h"
NTSTATUS RtlAllocateStringInPool( ULONG ulFlags, PRTL_STRING_POOL pStringPool, PUNICODE_STRING pusOutbound, SIZE_T ulByteCount ) { NTSTATUS status; ULONG idx; PRTL_STRING_POOL_FRAME pFrameWithFreeSpace = NULL;
RtlZeroMemory(pusOutbound, sizeof(*pusOutbound));
if (!ARGUMENT_PRESENT(pStringPool) || !ARGUMENT_PRESENT(pusOutbound) || (ulByteCount >= 0xFFFF) ) { return STATUS_INVALID_PARAMETER; }
//
// Zing through frames in the string pool looking for a frame with
// enough bytes open
//
for (idx = 0; idx < pStringPool->ulFramesCount; idx++) {
status = RtlIndexIntoGrowingList( &pStringPool->FrameList, idx, (PVOID*)&pFrameWithFreeSpace, FALSE);
if (!NT_SUCCESS(status)) { return status; }
//
// There's space in this frame!
//
if (pFrameWithFreeSpace->cbRegionAvailable >= ulByteCount) { break; } }
//
// Frame not found, index one past the current limit, implicitly (potentially)
// allocating into the growing list
//
if (pFrameWithFreeSpace == NULL) {
status = RtlIndexIntoGrowingList( &pStringPool->FrameList, pStringPool->ulFramesCount, (PVOID*)&pFrameWithFreeSpace, TRUE);
if (!NT_SUCCESS(status)) { return status; }
//
// Requested byte count is larger than the bytes in a new region? Bump up the
// size of new regions to twice this size
//
if (ulByteCount > pStringPool->cbBytesInNewRegion) { pStringPool->cbBytesInNewRegion = ulByteCount * 2; }
status = pStringPool->Allocator.pfnAlloc( pStringPool->cbBytesInNewRegion, (PVOID*)&pFrameWithFreeSpace->pvRegion, pStringPool->Allocator.pvContext);
if (!NT_SUCCESS(status)) { return STATUS_NO_MEMORY; }
pFrameWithFreeSpace->pvNextAvailable = pFrameWithFreeSpace->pvRegion; pFrameWithFreeSpace->cbRegionAvailable = pStringPool->cbBytesInNewRegion; }
//
// Sanity checking
//
ASSERT(pFrameWithFreeSpace != NULL); ASSERT(pFrameWithFreeSpace->cbRegionAvailable >= ulByteCount);
//
// Bookkeeping in the frame
//
pFrameWithFreeSpace->cbRegionAvailable -= ulByteCount; pFrameWithFreeSpace->pvNextAvailable = (PVOID)(((ULONG_PTR)pFrameWithFreeSpace->pvNextAvailable) + ulByteCount);
//
// Set up the outbound thing
//
pusOutbound->Buffer = pFrameWithFreeSpace->pvNextAvailable; pusOutbound->MaximumLength = (USHORT)ulByteCount; pusOutbound->Length = 0;
return STATUS_SUCCESS; }
NTSTATUS RtlDestroyStringPool( PRTL_STRING_POOL pStringPool ) { NTSTATUS status; PRTL_STRING_POOL_FRAME pFrame = NULL; ULONG ul;
//
// Zing through frames and deallocate those that weren't allocated
// inline with the pool
//
for (ul = 0; ul < pStringPool->ulFramesCount; ul++) {
status = RtlIndexIntoGrowingList( &pStringPool->FrameList, ul, (PVOID*)&pFrame, FALSE);
if (!NT_SUCCESS(status)) { return status; }
if ((pFrame->ulFlags & RTL_STRING_POOL_FRAME_FLAG_REGION_INLINE) == 0) {
status = pStringPool->Allocator.pfnFree(pFrame->pvRegion, pStringPool->Allocator.pvContext); pFrame->pvRegion = NULL; pFrame->pvNextAvailable = NULL; pFrame->cbRegionAvailable = 0;
} }
//
// We're done, destroy the list itself
//
status = RtlDestroyGrowingList(&pStringPool->FrameList); if (!NT_SUCCESS(status)) { return status; }
//
// No frames, list destroyed
//
pStringPool->ulFramesCount = 0;
//
// Great.
//
return STATUS_SUCCESS; }
NTSTATUS RtlCreateStringPool( ULONG ulFlags, PRTL_STRING_POOL pStringPool, SIZE_T cbBytesInFrames, PRTL_ALLOCATOR Allocator, PVOID pvOriginalRegion, SIZE_T cbOriginalRegion ) { NTSTATUS status;
//
// Ick. Heap allocation all the way
//
if ((cbOriginalRegion == 0) || (pvOriginalRegion == NULL)) { status = RtlInitializeGrowingList( &pStringPool->FrameList, sizeof(RTL_STRING_POOL_FRAME), 20, NULL, 0, Allocator);
pStringPool->ulFramesCount = 0; pStringPool->Allocator = *Allocator; pStringPool->cbBytesInNewRegion = cbBytesInFrames; return STATUS_SUCCESS; } //
// Good, space for at least one frame, donate the remainder to the list
//
else if (cbOriginalRegion >= sizeof(RTL_STRING_POOL_FRAME)) {
RTL_STRING_POOL_FRAME* pFirstFrame = NULL;
status = RtlInitializeGrowingList( &pStringPool->FrameList, sizeof(RTL_STRING_POOL_FRAME), 20, pvOriginalRegion, sizeof(RTL_STRING_POOL_FRAME), Allocator);
pStringPool->ulFramesCount = pStringPool->FrameList.cInternalElements; pStringPool->Allocator = *Allocator; pStringPool->cbBytesInNewRegion = cbBytesInFrames;
if (pStringPool->ulFramesCount) { status = RtlIndexIntoGrowingList( &pStringPool->FrameList, 0, (PVOID*)&pFirstFrame, FALSE);
//
// Wierd...
//
if ((status == STATUS_NO_MEMORY) || (status == STATUS_NOT_FOUND)) { pStringPool->ulFramesCount = 0; } else { pFirstFrame->pvRegion = pFirstFrame->pvNextAvailable = (PVOID)(((ULONG_PTR)pvOriginalRegion) + sizeof(RTL_STRING_POOL_FRAME)); pFirstFrame->cbRegionAvailable = cbOriginalRegion - sizeof(RTL_STRING_POOL_FRAME); pFirstFrame->ulFlags = RTL_STRING_POOL_FRAME_FLAG_REGION_INLINE; } }
return STATUS_SUCCESS; }
return STATUS_INVALID_PARAMETER;
}
|