|
|
/****************************** Module Header ******************************\
* Module Name: rtlinit.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * History: * 14-Jan-1991 mikeke \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/**************************************************************************\
* RtlCaptureAnsiString * * Converts a NULL-terminated ANSI string into a counted unicode string. * * 03-22-95 JimA Created. \**************************************************************************/ BOOL RtlCaptureAnsiString( PIN_STRING pstr, LPCSTR psz, BOOL fForceAlloc) { int cbSrc, cbDst; NTSTATUS Status;
pstr->fAllocated = FALSE; if (psz) { cbSrc = strlen(psz) + 1; if (cbSrc > MAXUSHORT) { RIPMSG0(RIP_WARNING, "String too long for standard string"); return FALSE; }
/*
* If the allocation is forced or if the string is too long to fit * in the TEB, allocate a buffer. Otherwise, store the result in the * TEB. */ if (fForceAlloc || cbSrc > (STATIC_UNICODE_BUFFER_LENGTH / sizeof(WCHAR))) { pstr->strCapture.Buffer = UserLocalAlloc(0, cbSrc * sizeof(WCHAR)); if (pstr->strCapture.Buffer == NULL) { return FALSE; } pstr->fAllocated = TRUE; pstr->pstr = &pstr->strCapture; pstr->strCapture.MaximumLength = (USHORT)(cbSrc * sizeof(WCHAR)); } else { pstr->pstr = &NtCurrentTeb()->StaticUnicodeString; }
/*
* Convert the string to Unicode. */ Status = RtlMultiByteToUnicodeN(pstr->pstr->Buffer, (ULONG)pstr->pstr->MaximumLength, &cbDst, (LPSTR)psz, cbSrc); if (!NT_SUCCESS(Status)) { RIPMSG0(RIP_WARNING, "Unicode conversion failed"); if (pstr->fAllocated) { UserLocalFree(pstr->strCapture.Buffer); pstr->fAllocated = FALSE; }
return FALSE; } pstr->pstr->Length = (USHORT)cbDst - sizeof(WCHAR); } else { pstr->pstr = &pstr->strCapture; pstr->strCapture.Length = pstr->strCapture.MaximumLength = 0; pstr->strCapture.Buffer = NULL; }
return TRUE; }
/**************************************************************************\
* RtlCaptureLargeAnsiString * * Captures a large ANSI string in the same manner as RtlCaptureAnsiString. * * 03-22-95 JimA Created. \**************************************************************************/ BOOL RtlCaptureLargeAnsiString( PLARGE_IN_STRING plstr, LPCSTR psz, BOOL fForceAlloc) { int cchSrc; UINT uLength; NTSTATUS Status;
plstr->fAllocated = FALSE; plstr->strCapture.bAnsi = FALSE; plstr->pstr = &plstr->strCapture;
if (psz) { cchSrc = strlen(psz) + 1;
/*
* If the allocation is forced or if the string is too long to fit * in the TEB, allocate a buffer. Otherwise, store the result in the * TEB. */ if (fForceAlloc || cchSrc > STATIC_UNICODE_BUFFER_LENGTH) { plstr->strCapture.Buffer = UserLocalAlloc(0, cchSrc * sizeof(WCHAR)); if (plstr->strCapture.Buffer == NULL) { return FALSE; } plstr->fAllocated = TRUE; plstr->strCapture.MaximumLength = cchSrc * sizeof(WCHAR); } else { plstr->strCapture.Buffer = NtCurrentTeb()->StaticUnicodeBuffer; plstr->strCapture.MaximumLength = (UINT)(STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR)); }
/*
* Convert the string to Unicode. */ Status = RtlMultiByteToUnicodeN(KPWSTR_TO_PWSTR(plstr->pstr->Buffer), plstr->pstr->MaximumLength, &uLength, (LPSTR)psz, cchSrc); if (!NT_SUCCESS(Status)) { RIPMSG0(RIP_WARNING, "Unicode conversion failed"); if (plstr->fAllocated) { UserLocalFree(KPWSTR_TO_PWSTR(plstr->strCapture.Buffer)); plstr->fAllocated = FALSE; } return FALSE; } plstr->pstr->Length = uLength - sizeof(WCHAR); } else { plstr->strCapture.Length = plstr->strCapture.MaximumLength = 0; plstr->strCapture.Buffer = NULL; }
return TRUE; }
/**************************************************************************\
* AllocateFromZone * * This routine removes an entry from the zone and returns a pointer to it. * * Arguments: * * Zone - Pointer to the zone header controlling the storage from which the * entry is to be allocated. * * Return Value: * * The function value is a pointer to the storage allocated from the zone. \**************************************************************************/ __inline PVOID AllocateFromZone( PZONE_HEADER Zone) { PVOID ptr = (PVOID)(Zone->FreeList.Next);
if (Zone->FreeList.Next) { Zone->FreeList.Next = Zone->FreeList.Next->Next; }
return ptr; }
/**************************************************************************\
* FreeToZone * * This routine places the specified block of storage back onto the free * list in the specified zone. * * Arguments: * * Zone - Pointer to the zone header controlling the storage to which the * entry is to be inserted. * * Block - Pointer to the block of storage to be freed back to the zone. * * Return Value: * * Pointer to previous block of storage that was at the head of the free * list. NULL implies the zone went from no available free blocks to at * least one free block. \**************************************************************************/ __inline VOID FreeToZone( PZONE_HEADER Zone, PVOID Block) { ((PSINGLE_LIST_ENTRY)Block)->Next = Zone->FreeList.Next; Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)Block; }
/***************************************************************************\
* InitLookaside * * Initializes the lookaside list. This improves control locality by keeping * control entries in a single page * * 05-04-95 JimA Created. \***************************************************************************/ NTSTATUS InitLookaside( PLOOKASIDE pla, DWORD cbEntry, DWORD cEntries) { ULONG i; PCH p; ULONG BlockSize; PZONE_HEADER Zone; PVOID InitialSegment; ULONG InitialSegmentSize;
InitialSegmentSize = (cEntries * cbEntry) + sizeof(ZONE_SEGMENT_HEADER);
p = (PCH)UserLocalAlloc(0, InitialSegmentSize); if (!p) { return STATUS_NO_MEMORY; }
RtlEnterCriticalSection(&gcsLookaside);
//
// If the lookaside list has already been initialized, we're done.
//
if (pla->LookasideBase != NULL && pla->EntrySize == cbEntry) { RtlLeaveCriticalSection(&gcsLookaside); UserLocalFree(p); return STATUS_SUCCESS; }
pla->LookasideBase = (PVOID)p; pla->LookasideBounds = (PVOID)(p + InitialSegmentSize); pla->EntrySize = cbEntry;
//
// Using the ExZone-like code, slice up the page into QMSG's
//
Zone = &pla->LookasideZone; BlockSize = cbEntry; InitialSegment = pla->LookasideBase;
Zone->BlockSize = BlockSize;
Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList; ((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList.Next = NULL; ((PZONE_SEGMENT_HEADER) InitialSegment)->Reserved = NULL;
Zone->FreeList.Next = NULL;
p = (PCH)InitialSegment + sizeof(ZONE_SEGMENT_HEADER);
for (i = sizeof(ZONE_SEGMENT_HEADER); i <= InitialSegmentSize - BlockSize; i += BlockSize) { ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next; Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p; p += BlockSize; } Zone->TotalSegmentSize = i;
RtlLeaveCriticalSection(&gcsLookaside);
return STATUS_SUCCESS;
}
/***************************************************************************\
* AllocLookasideEntry * * Allocates an entry from the lookaside list. * * 05-04-95 JimA Created. \***************************************************************************/ PVOID AllocLookasideEntry( PLOOKASIDE pla) { PVOID pEntry;
//
// Attempt to get an entry from the zone. If this fails, then
// UserLocalAlloc the entry.
//
RtlEnterCriticalSection(&gcsLookaside); pEntry = AllocateFromZone(&pla->LookasideZone); RtlLeaveCriticalSection(&gcsLookaside);
if (!pEntry) { /*
* Allocate a local structure. */ #if DBG
pla->AllocSlowCalls++; #endif
if ((pEntry = UserLocalAlloc(0, pla->EntrySize)) == NULL) { return NULL; } } RtlZeroMemory(pEntry, pla->EntrySize);
#if DBG
pla->AllocCalls++;
if (pla->AllocCalls - pla->DelCalls > pla->AllocHiWater) { pla->AllocHiWater = pla->AllocCalls - pla->DelCalls; } #endif
return pEntry; }
/***************************************************************************\
* FreeLookasideEntry * * Returns a qmsg to the lookaside buffer or free the memory. * * 05-04-95 JimA Created. \***************************************************************************/ VOID FreeLookasideEntry( PLOOKASIDE pla, PVOID pEntry) { #if DBG
pla->DelCalls++; #endif
//
// If the pEntry was from zone, then free to zone.
//
if ((PVOID)pEntry >= pla->LookasideBase && (PVOID)pEntry < pla->LookasideBounds) { RtlEnterCriticalSection(&gcsLookaside); FreeToZone(&pla->LookasideZone, pEntry); RtlLeaveCriticalSection(&gcsLookaside); } else { #if DBG
pla->DelSlowCalls++; #endif
UserLocalFree(pEntry); } }
|