Leaked source code of windows server 2003
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.
 
 
 
 
 
 

408 lines
9.8 KiB

#include "nt.h"
#include "ntdef.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "generichandles.h"
NTSTATUS
RtlpGenericTableAddSlots(
PGENERIC_HANDLE_TABLE pCreatedTable,
PGENERIC_HANDLE_SLOT pSlots,
USHORT usSlots
)
{
NTSTATUS status = STATUS_SUCCESS;
USHORT us;
ASSERT(pCreatedTable != NULL);
ASSERT(pSlots != NULL);
ASSERT(usSlots > 0);
RtlZeroMemory(pSlots, sizeof(GENERIC_HANDLE_SLOT) * usSlots);
//
// Next, next, next
//
for (us = 0; us < (usSlots - 1); us++) {
pSlots[us].pNextFree = pSlots + (us + 1);
}
//
// If there were no free slots, set this run as the new list of free
// slots. Otherwise, set this as the "next available" free slot
//
if (pCreatedTable->pFirstFreeSlot != NULL) {
pCreatedTable->pFirstFreeSlot->pNextFree = pSlots;
}
//
// Add these to the list of slots
//
pCreatedTable->usSlotCount += usSlots;
//
// If there was no set of slots on the table already, then add these as the
// current list of slots
//
if (pCreatedTable->pSlots == NULL) {
pCreatedTable->pSlots = pSlots;
}
pCreatedTable->pFirstFreeSlot = pSlots;
return status;
}
NTSTATUS
RtlCreateGenericHandleTable(
ULONG ulFlags,
PGENERIC_HANDLE_TABLE pCreatedTable,
PFNHANDLETABLEALLOC pfnAlloc,
PFNHANDLETABLEFREE pfnFree,
SIZE_T ulcbOriginalBlob,
PVOID pvOriginalBlob
)
{
NTSTATUS status = STATUS_SUCCESS;
if ((ulFlags != 0) || (pCreatedTable == NULL) || (ulcbOriginalBlob && !pvOriginalBlob)) {
return STATUS_INVALID_PARAMETER;
}
RtlZeroMemory(pCreatedTable, sizeof(*pCreatedTable));
pCreatedTable->pfnAlloc = pfnAlloc;
pCreatedTable->pfnFree = pfnFree;
pCreatedTable->ulFlags = ulFlags;
pCreatedTable->usInlineHandleSlots = (USHORT)(ulcbOriginalBlob / sizeof(GENERIC_HANDLE_SLOT));
//
// If there were slots handed to us, then initialize the table to use those first
//
if (pCreatedTable->usInlineHandleSlots > 0) {
pCreatedTable->pInlineHandleSlots = (PGENERIC_HANDLE_SLOT)pvOriginalBlob;
//
// Now, add the slots that we were handed into the free list
//
status = RtlpGenericTableAddSlots(
pCreatedTable,
pCreatedTable->pSlots,
pCreatedTable->usInlineHandleSlots);
}
//
// Otherwise, everything is zero-initted already, so just bop out
//
return status;
}
NTSTATUS
RtlCreateGenericHandleTableInPlace(
ULONG ulFlags,
SIZE_T cbInPlace,
PVOID pvPlace,
PFNHANDLETABLEALLOC pfnAlloc,
PFNHANDLETABLEFREE pfnFree,
PGENERIC_HANDLE_TABLE *ppCreatedTable
)
{
NTSTATUS status;
if ((pvPlace == NULL) || (cbInPlace && !pvPlace) || !ppCreatedTable) {
return STATUS_INVALID_PARAMETER;
}
else if (cbInPlace < sizeof(GENERIC_HANDLE_TABLE)) {
return STATUS_BUFFER_TOO_SMALL;
}
*ppCreatedTable = (PGENERIC_HANDLE_TABLE)pvPlace;
status = RtlCreateGenericHandleTable(
ulFlags,
*ppCreatedTable,
pfnAlloc,
pfnFree,
cbInPlace - sizeof(GENERIC_HANDLE_TABLE),
*ppCreatedTable + 1);
return status;
}
#define HANDLE_TABLE_SLOT_MASK (0x0000FFFF)
#define HANDLE_TABLE_GEN_FLAG_SHIFT (16)
#define HANDLE_TABLE_IN_USE_FLAG (0x8000)
#define HANDLE_TABLE_GENERATION_MASK (~HANDLE_TABLE_IN_USE_FLAG)
NTSTATUS
RtlpFindSlotForHandle(
PGENERIC_HANDLE_TABLE pHandleTable,
PVOID pvHandle,
PGENERIC_HANDLE_SLOT *ppSlot
)
{
PGENERIC_HANDLE_SLOT pSlot;
USHORT usSlotEntry = (USHORT)((ULONG_PTR)pvHandle & HANDLE_TABLE_SLOT_MASK);
USHORT usGeneration = (USHORT)((ULONG_PTR)pvHandle >> HANDLE_TABLE_GEN_FLAG_SHIFT);
pSlot = pHandleTable->pSlots + usSlotEntry;
//
// Generation flag not in use, gen mismatch, or not in the table? Oops.
//
if (((usGeneration & HANDLE_TABLE_IN_USE_FLAG) == 0) ||
(usSlotEntry >= pHandleTable->usSlotCount) ||
(pSlot->usGenerationFlag != usGeneration)) {
return STATUS_NOT_FOUND;
}
//
// Return that the slot was found
//
else {
*ppSlot = pSlot;
return STATUS_SUCCESS;
}
}
NTSTATUS
RtlAddRefGenericHandle(
PGENERIC_HANDLE_TABLE pHandleTable,
PVOID pvGenericHandle
)
{
PGENERIC_HANDLE_SLOT pSlot;
NTSTATUS status;
if (pHandleTable == NULL) {
return STATUS_INVALID_PARAMETER;
}
status = RtlpFindSlotForHandle(pHandleTable, pvGenericHandle, &pSlot);
if (!NT_SUCCESS(status)) {
return status;
}
pSlot->ulRefCount++;
return STATUS_SUCCESS;
}
NTSTATUS
RtlReleaseGenericHandle(
PGENERIC_HANDLE_TABLE pHandleTable,
PVOID pvGenericHandle
)
{
PGENERIC_HANDLE_SLOT pSlot;
NTSTATUS status;
if (pHandleTable == NULL) {
return STATUS_INVALID_PARAMETER;
}
status = RtlpFindSlotForHandle(pHandleTable, pvGenericHandle, &pSlot);
if (!NT_SUCCESS(status)) {
return status;
}
pSlot->ulRefCount--;
return STATUS_SUCCESS;
}
NTSTATUS
RtlRemoveGenericHandle(
PGENERIC_HANDLE_TABLE pHandleTable,
ULONG ulFlags,
PVOID pvObjectHandle
)
{
PGENERIC_HANDLE_SLOT pSlot = NULL;
NTSTATUS status;
if ((pHandleTable == NULL) || (ulFlags != 0)) {
return STATUS_INVALID_PARAMETER;
}
status = RtlpFindSlotForHandle(pHandleTable, pvObjectHandle, &pSlot);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Flip the in-use flag
//
pSlot->usGenerationFlag &= ~HANDLE_TABLE_IN_USE_FLAG;
pSlot->pNextFree = pHandleTable->pFirstFreeSlot;
pHandleTable->pFirstFreeSlot = pSlot;
return STATUS_SUCCESS;
}
NTSTATUS
RtlDereferenceHandle(
PGENERIC_HANDLE_TABLE pHandleTable,
PVOID pvGenericHandle,
PVOID *ppvObjectPointer
)
{
USHORT usSlotEntry;
NTSTATUS status;
PGENERIC_HANDLE_SLOT pSlot = NULL;
if ((pHandleTable == NULL) || (pvGenericHandle == NULL) || (ppvObjectPointer == NULL)) {
return STATUS_INVALID_PARAMETER;
}
*ppvObjectPointer = NULL;
status = RtlpFindSlotForHandle(pHandleTable, pvGenericHandle, &pSlot);
if (!NT_SUCCESS(status)) {
return status;
}
*ppvObjectPointer = pSlot->pvThisHandle;
return STATUS_SUCCESS;
}
NTSTATUS
RtlpExpandGenericHandleTable(
PGENERIC_HANDLE_TABLE pHandleTable,
ULONG ulNewSlotCount
)
{
PGENERIC_HANDLE_SLOT pNewSlots = NULL;
NTSTATUS status;
//
// New slot count is 0? Make it 20 instead.
//
if (ulNewSlotCount == 0) {
ulNewSlotCount = pHandleTable->usSlotCount + 20;
}
//
// Did we fly out of range?
//
if (ulNewSlotCount > 0xFFFF) {
ulNewSlotCount = 0xFFFF;
//
// Can't allocate more, the table is full
//
if (ulNewSlotCount == pHandleTable->usSlotCount) {
return STATUS_NO_MEMORY;
}
}
//
// Don't ever do this if there are free slots left in the table
//
ASSERT(pHandleTable->pFirstFreeSlot == NULL);
status = pHandleTable->pfnAlloc(sizeof(GENERIC_HANDLE_SLOT) * ulNewSlotCount, (PVOID*)&pNewSlots);
if (!NT_SUCCESS(status)) {
return status;
}
return status;
}
NTSTATUS
RtlAddGenericHandle(
PGENERIC_HANDLE_TABLE pHandleTable,
ULONG ulFlags,
PVOID pvObject,
PVOID *ppvObjectHandle
)
{
PGENERIC_HANDLE_SLOT pSlot = NULL;
NTSTATUS status;
if (ppvObjectHandle)
*ppvObjectHandle = NULL;
if ((pHandleTable == NULL) || (ulFlags != 0) || (pvObject != NULL) || (ppvObjectHandle == NULL)) {
return STATUS_INVALID_PARAMETER;
}
if (pHandleTable->pFirstFreeSlot == NULL) {
status = RtlpExpandGenericHandleTable(pHandleTable, (pHandleTable->usSlotCount * 3) / 2);
if (!NT_SUCCESS(status)) {
return status;
}
}
ASSERT(pHandleTable->pFirstFreeSlot != NULL);
//
// Adjust free list
//
pSlot = pHandleTable->pFirstFreeSlot;
pHandleTable->pFirstFreeSlot = pSlot->pNextFree;
//
// Set up the various flags.
//
ASSERT((pSlot->usGenerationFlag & HANDLE_TABLE_IN_USE_FLAG) == 0);
//
// Increment the generation flag, set the in-use flag
//
pSlot->usGenerationFlag = (pSlot->usGenerationFlag & HANDLE_TABLE_GENERATION_MASK) + 1;
pSlot->usGenerationFlag |= HANDLE_TABLE_IN_USE_FLAG;
pSlot->ulRefCount = 0;
//
// Record the object pointer
//
pSlot->pvThisHandle = pvObject;
//
// The object handle is composed of 16 bits of generation mask plus the top-bit set
// (which nicely avoids people casting it to a pointer that they can use), and
// the lower 16 bits of "slot number", or an index into the handle table.
//
*ppvObjectHandle = (PVOID)((ULONG_PTR)(
(pSlot->usGenerationFlag << HANDLE_TABLE_GEN_FLAG_SHIFT) |
((pSlot - pHandleTable->pInlineHandleSlots) & HANDLE_TABLE_SLOT_MASK)));
return STATUS_SUCCESS;
}