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.
248 lines
6.5 KiB
248 lines
6.5 KiB
#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;
|
|
|
|
}
|
|
|