dvander@370: /** ds@653: * vim: set ts=4 : dvander@370: * =============================================================== dvander@370: * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. dvander@370: * =============================================================== dvander@370: * dvander@370: * This file is not open source and may not be copied without explicit dvander@370: * written permission of AlliedModders LLC. This file may not be redistributed dvander@370: * in whole or significant part. dvander@370: * For information, see LICENSE.txt or http://www.sourcemod.net/license.php dvander@370: * dvander@370: * Version: $Id$ dvander@370: */ dvander@370: dvander@218: #include "HandleSys.h" dvander@229: #include "ShareSys.h" dvander@218: #include "PluginSys.h" dvander@222: #include dvander@351: #include dvander@218: dvander@218: HandleSystem g_HandleSys; dvander@218: dvander@229: QHandle *ignore_handle; dvander@229: dvander@229: inline HandleType_t TypeParent(HandleType_t type) dvander@229: { dvander@229: return (type & ~HANDLESYS_SUBTYPE_MASK); dvander@229: } dvander@229: dvander@229: inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index) dvander@229: { dvander@262: return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index); dvander@229: } dvander@229: dvander@218: HandleSystem::HandleSystem() dvander@218: { dvander@218: m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1]; dvander@218: memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1)); dvander@218: dvander@218: m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE]; dvander@218: memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE); dvander@218: dvander@218: m_TypeLookup = sm_trie_create(); dvander@218: m_strtab = new BaseStringTable(512); dvander@218: dvander@218: m_TypeTail = 0; dvander@218: } dvander@218: dvander@218: HandleSystem::~HandleSystem() dvander@218: { dvander@218: delete [] m_Handles; dvander@218: delete [] m_Types; dvander@218: sm_trie_destroy(m_TypeLookup); dvander@218: delete m_strtab; dvander@218: } dvander@218: dvander@218: dvander@262: HandleType_t HandleSystem::CreateType(const char *name, dvander@262: IHandleTypeDispatch *dispatch, dvander@262: HandleType_t parent, dvander@262: const TypeAccess *typeAccess, dvander@262: const HandleAccess *hndlAccess, dvander@262: IdentityToken_t *ident, dvander@262: HandleError *err) dvander@218: { dvander@218: if (!dispatch) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Parameter; dvander@262: } dvander@262: return 0; dvander@262: } dvander@262: dvander@262: if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) dvander@262: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Version; dvander@262: } dvander@262: return 0; dvander@262: } dvander@262: dvander@262: if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) dvander@262: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Version; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: dvander@218: bool isChild = false; dvander@218: dvander@218: if (parent != 0) dvander@218: { dvander@218: isChild = true; dvander@218: if (parent & HANDLESYS_SUBTYPE_MASK) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_NoInherit; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: if (parent >= HANDLESYS_TYPEARRAY_SIZE dvander@262: || m_Types[parent].dispatch == NULL) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Parameter; dvander@262: } dvander@262: return 0; dvander@262: } dvander@262: if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false dvander@262: && (m_Types[parent].typeSec.ident != ident)) dvander@262: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Access; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: } dvander@218: dvander@262: if (name && name[0] != '\0') dvander@218: { dvander@262: if (sm_trie_retrieve(m_TypeLookup, name, NULL)) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Parameter; dvander@262: } dvander@262: return 0; dvander@218: } dvander@218: } dvander@218: dvander@218: unsigned int index; dvander@218: dvander@218: if (isChild) dvander@218: { dvander@218: QHandleType *pParent = &m_Types[parent]; dvander@218: if (pParent->children >= HANDLESYS_MAX_SUBTYPES) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Limit; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: index = 0; dvander@218: for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++) dvander@218: { dvander@218: if (m_Types[parent + i].dispatch == NULL) dvander@218: { dvander@218: index = parent + i; dvander@218: break; dvander@218: } dvander@218: } dvander@218: if (!index) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Limit; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: pParent->children++; dvander@218: } else { dvander@218: if (m_FreeTypes == 0) dvander@218: { dvander@218: /* Reserve another index */ dvander@218: if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Limit; dvander@262: } dvander@218: return 0; dvander@218: } else { dvander@218: m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1); dvander@218: index = m_TypeTail; dvander@218: } dvander@218: } else { dvander@218: /* The "free array" is compacted into the normal array for easiness */ dvander@218: index = m_Types[m_FreeTypes--].freeID; dvander@218: } dvander@218: } dvander@218: dvander@218: QHandleType *pType = &m_Types[index]; dvander@218: dvander@218: pType->dispatch = dispatch; dvander@218: if (name && name[0] != '\0') dvander@218: { dvander@218: pType->nameIdx = m_strtab->AddString(name); dvander@218: sm_trie_insert(m_TypeLookup, name, (void *)pType); dvander@218: } else { dvander@218: pType->nameIdx = -1; dvander@218: } dvander@262: dvander@218: pType->opened = 0; dvander@218: dvander@262: if (typeAccess) dvander@262: { dvander@262: pType->typeSec = *typeAccess; dvander@262: } else { dvander@262: InitAccessDefaults(&pType->typeSec, NULL); dvander@262: pType->typeSec.ident = ident; dvander@262: } dvander@262: dvander@262: if (hndlAccess) dvander@262: { dvander@262: pType->hndlSec = *hndlAccess; dvander@262: } else { dvander@262: InitAccessDefaults(NULL, &pType->hndlSec); dvander@262: } dvander@262: dvander@218: if (!isChild) dvander@218: { dvander@218: pType->children = 0; dvander@218: } dvander@218: dvander@218: return index; dvander@218: } dvander@218: dvander@218: bool HandleSystem::FindHandleType(const char *name, HandleType_t *type) dvander@218: { dvander@218: QHandleType *_type; dvander@218: dvander@218: if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type)) dvander@218: { dvander@218: return false; dvander@218: } dvander@218: dvander@218: unsigned int offset = _type - m_Types; dvander@218: dvander@218: if (type) dvander@218: { dvander@218: *type = offset; dvander@218: } dvander@218: dvander@218: return true; dvander@218: } dvander@218: dvander@222: HandleError HandleSystem::MakePrimHandle(HandleType_t type, dvander@222: QHandle **in_pHandle, dvander@222: unsigned int *in_index, dvander@229: Handle_t *in_handle, dvander@283: IdentityToken_t *owner, dvander@283: bool identity) dvander@222: { dvander@229: unsigned int owner_index = 0; dvander@229: dvander@229: if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None)) dvander@229: { dvander@229: return HandleError_Identity; dvander@229: } dvander@229: dvander@222: unsigned int handle; dvander@222: if (m_FreeHandles == 0) dvander@222: { dvander@222: if (m_HandleTail >= HANDLESYS_MAX_HANDLES) dvander@222: { dvander@222: return HandleError_Limit;; dvander@222: } dvander@222: handle = ++m_HandleTail; dvander@222: } else { dvander@222: handle = m_Handles[m_FreeHandles--].freeID; dvander@222: } dvander@222: dvander@222: QHandle *pHandle = &m_Handles[handle]; dvander@222: dvander@222: assert(pHandle->set == false); dvander@222: dvander@222: if (++m_HSerial >= HANDLESYS_MAX_SERIALS) dvander@222: { dvander@222: m_HSerial = 1; dvander@222: } dvander@222: dvander@222: /* Set essential information */ dvander@283: pHandle->set = identity ? HandleSet_Identity : HandleSet_Used; dvander@222: pHandle->refcount = 1; dvander@222: pHandle->type = type; dvander@222: pHandle->serial = m_HSerial; dvander@229: pHandle->owner = owner; dvander@229: pHandle->ch_next = 0; dvander@528: pHandle->access_special = false; dvander@222: dvander@222: /* Create the hash value */ dvander@222: Handle_t hash = pHandle->serial; dvander@222: hash <<= 16; dvander@222: hash |= handle; dvander@222: dvander@222: /* Add a reference count to the type */ dvander@222: m_Types[type].opened++; dvander@222: dvander@222: /* Output */ dvander@222: *in_pHandle = pHandle; dvander@222: *in_index = handle; dvander@222: *in_handle = hash; dvander@222: dvander@283: /* Decode the identity token dvander@283: * For now, we don't allow nested ownership dvander@283: */ dvander@283: if (owner && !identity) dvander@229: { dvander@229: QHandle *pIdentity = &m_Handles[owner_index]; dvander@229: if (pIdentity->ch_prev == 0) dvander@229: { dvander@229: pIdentity->ch_prev = handle; dvander@229: pIdentity->ch_next = handle; dvander@229: pHandle->ch_prev = 0; dvander@229: } else { dvander@229: /* Link previous node to us (forward) */ dvander@229: m_Handles[pIdentity->ch_next].ch_next = handle; dvander@229: /* Link us to previous node (backwards) */ dvander@229: pHandle->ch_prev = pIdentity->ch_next; dvander@229: /* Set new tail */ dvander@229: pIdentity->ch_next = handle; dvander@229: } dvander@229: pIdentity->refcount++; dvander@229: } else { dvander@229: pHandle->ch_prev = 0; dvander@229: } dvander@229: dvander@222: return HandleError_None; dvander@222: } dvander@222: dvander@229: void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken) dvander@229: { dvander@229: if (!type dvander@229: || type >= HANDLESYS_TYPEARRAY_SIZE dvander@229: || m_Types[type].dispatch == NULL) dvander@229: { dvander@229: return; dvander@229: } dvander@229: dvander@262: m_Types[type].typeSec.ident = pToken; dvander@229: } dvander@229: dvander@528: Handle_t HandleSystem::CreateHandleInt(HandleType_t type, dvander@528: void *object, dvander@528: const HandleSecurity *pSec, dvander@528: HandleError *err, dvander@528: const HandleAccess *pAccess, dvander@528: bool identity) dvander@218: { dvander@528: IdentityToken_t *ident; dvander@528: IdentityToken_t *owner; dvander@528: dvander@528: if (pSec) dvander@528: { dvander@528: ident = pSec->pIdentity; dvander@528: owner = pSec->pOwner; dvander@528: } else { dvander@528: ident = NULL; dvander@528: owner = NULL; dvander@528: } dvander@528: dvander@218: if (!type dvander@218: || type >= HANDLESYS_TYPEARRAY_SIZE dvander@218: || m_Types[type].dispatch == NULL) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Parameter; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: dvander@262: /* Check to see if we're allowed to create this handle type */ dvander@218: QHandleType *pType = &m_Types[type]; dvander@262: if (!pType->typeSec.access[HTypeAccess_Create] dvander@283: && (!pType->typeSec.ident dvander@283: || pType->typeSec.ident != ident)) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = HandleError_Access; dvander@262: } dvander@218: return 0; dvander@218: } dvander@218: dvander@222: unsigned int index; dvander@222: Handle_t handle; dvander@222: QHandle *pHandle; dvander@262: HandleError _err; dvander@222: dvander@283: if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None) dvander@218: { dvander@262: if (err) dvander@262: { dvander@262: *err = _err; dvander@262: } dvander@222: return 0; dvander@218: } dvander@218: dvander@528: if (pAccess) dvander@528: { dvander@528: pHandle->access_special = true; dvander@528: pHandle->sec = *pAccess; dvander@528: } dvander@528: dvander@218: pHandle->object = object; dvander@222: pHandle->clone = 0; dvander@218: dvander@222: return handle; dvander@218: } dvander@218: dvander@528: Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err) dvander@528: { dvander@528: return CreateHandleInt(type, object, pSec, err, pAccess, false); dvander@528: } dvander@528: dvander@283: Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err) dvander@283: { dvander@528: HandleSecurity sec; dvander@528: dvander@528: sec.pIdentity = ident; dvander@528: sec.pOwner = owner; dvander@528: dvander@528: return CreateHandleEx(type, object, &sec, NULL, err); dvander@283: } dvander@283: dvander@229: bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) dvander@229: { dvander@229: /* Check the type inheritance */ dvander@229: if (intype & HANDLESYS_SUBTYPE_MASK) dvander@229: { dvander@229: if (intype != outtype dvander@229: && (TypeParent(intype) != TypeParent(outtype))) dvander@229: { dvander@229: return false; dvander@229: } dvander@229: } else { dvander@229: if (intype != outtype) dvander@229: { dvander@229: return false; dvander@229: } dvander@229: } dvander@229: dvander@229: return true; dvander@229: } dvander@229: dvander@222: HandleError HandleSystem::GetHandle(Handle_t handle, dvander@229: IdentityToken_t *ident, dvander@222: QHandle **in_pHandle, dvander@222: unsigned int *in_index, dvander@259: bool ignoreFree) dvander@218: { dvander@218: unsigned int serial = (handle >> 16); dvander@218: unsigned int index = (handle & HANDLESYS_HANDLE_MASK); dvander@218: dvander@218: if (index == 0 || index == 0xFFFF) dvander@218: { dvander@218: return HandleError_Index; dvander@218: } dvander@218: dvander@218: QHandle *pHandle = &m_Handles[index]; dvander@218: dvander@259: if (!pHandle->set dvander@259: || (pHandle->set == HandleSet_Freed && !ignoreFree)) dvander@218: { dvander@218: return HandleError_Freed; dvander@229: } else if (pHandle->set == HandleSet_Identity dvander@229: && ident != g_ShareSys.GetIdentRoot()) dvander@229: { dvander@229: /* Only IdentityHandle() can read this! */ dvander@229: return HandleError_Identity; dvander@218: } dvander@218: if (pHandle->serial != serial) dvander@218: { dvander@218: return HandleError_Changed; dvander@218: } dvander@218: dvander@222: *in_pHandle = pHandle; dvander@222: *in_index = index; dvander@222: dvander@222: return HandleError_None; dvander@222: } dvander@222: dvander@262: bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity) dvander@262: { dvander@262: QHandleType *pType = &m_Types[pHandle->type]; dvander@528: unsigned int access; dvander@528: dvander@528: if (pHandle->access_special) dvander@528: { dvander@528: access = pHandle->sec.access[right]; dvander@528: } else { dvander@528: access = pType->hndlSec.access[right]; dvander@528: } dvander@262: dvander@262: /* Check if the type's identity matches */ dvander@262: if (access & HANDLE_RESTRICT_IDENTITY) dvander@262: { dvander@262: IdentityToken_t *owner = pType->typeSec.ident; dvander@262: if (!owner dvander@262: || (!pSecurity || pSecurity->pIdentity != owner)) dvander@262: { dvander@262: return false; dvander@262: } dvander@262: } dvander@262: dvander@262: /* Check if the owner is allowed */ dvander@262: if (access & HANDLE_RESTRICT_OWNER) dvander@262: { dvander@262: IdentityToken_t *owner = pHandle->owner; dvander@262: if (owner dvander@262: && (!pSecurity || pSecurity->pOwner != owner)) dvander@262: { dvander@262: return false; dvander@262: } dvander@262: } dvander@262: dvander@262: return true; dvander@262: } dvander@262: dvander@283: HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner) dvander@283: { dvander@283: /* Get a new Handle ID */ dvander@283: unsigned int new_index; dvander@283: QHandle *pNewHandle; dvander@283: Handle_t new_handle; dvander@283: HandleError err; dvander@283: dvander@283: if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None) dvander@283: { dvander@283: return err; dvander@283: } dvander@283: dvander@528: /* Assign permissions from parent */ dvander@528: if (pHandle->access_special) dvander@528: { dvander@528: pNewHandle->access_special = true; dvander@528: pNewHandle->sec = pHandle->sec; dvander@528: } dvander@528: dvander@283: pNewHandle->clone = index; dvander@283: pHandle->refcount++; dvander@283: dvander@283: *newhandle = new_handle; dvander@283: dvander@283: return HandleError_None; dvander@283: } dvander@283: dvander@262: HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity) dvander@222: { dvander@222: HandleError err; dvander@222: QHandle *pHandle; dvander@222: unsigned int index; dvander@262: IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; dvander@222: dvander@262: if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) dvander@222: { dvander@222: return err; dvander@222: } dvander@222: dvander@259: /* Identities cannot be cloned */ dvander@259: if (pHandle->set == HandleSet_Identity) dvander@259: { dvander@259: return HandleError_Identity; dvander@259: } dvander@259: dvander@262: /* Check if the handle can be cloned */ dvander@262: if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity)) dvander@262: { dvander@262: return HandleError_Access; dvander@262: } dvander@222: dvander@283: /* Make sure we're not cloning a clone */ dvander@283: if (pHandle->clone) dvander@222: { dvander@283: QHandle *pParent = &m_Handles[pHandle->clone]; dvander@283: return CloneHandle(pParent, pHandle->clone, newhandle, newOwner); dvander@222: } dvander@222: dvander@283: return CloneHandle(pHandle, index, newhandle, newOwner); dvander@283: } dvander@283: dvander@283: HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index) dvander@283: { dvander@283: QHandleType *pType = &m_Types[pHandle->type]; dvander@283: dvander@283: if (pHandle->clone) dvander@283: { dvander@283: /* If we're a clone, decrease the parent reference count */ dvander@283: QHandle *pMaster; dvander@283: unsigned int master; dvander@283: dvander@283: /* Note that if we ever have per-handle security, we would need to re-check dvander@283: * the access on this Handle. */ dvander@283: master = pHandle->clone; dvander@283: pMaster = &m_Handles[master]; dvander@283: dvander@283: /* Release the clone now */ dvander@283: ReleasePrimHandle(index); dvander@222: dvander@283: /* Decrement the master's reference count */ dvander@283: if (--pMaster->refcount == 0) dvander@283: { dvander@283: /* Type should be the same but do this anyway... */ dvander@283: pType = &m_Types[pMaster->type]; dvander@283: pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object); dvander@283: ReleasePrimHandle(master); dvander@283: } dvander@283: } else if (pHandle->set == HandleSet_Identity) { dvander@283: /* If we're an identity, skip all this stuff! dvander@283: * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR dvander@283: */ dvander@283: ReleasePrimHandle(index); dvander@283: } else { dvander@283: /* Decrement, free if necessary */ dvander@283: if (--pHandle->refcount == 0) dvander@283: { dvander@283: pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); dvander@283: ReleasePrimHandle(index); dvander@283: } else { dvander@283: /* We must be cloned, so mark ourselves as freed */ dvander@283: pHandle->set = HandleSet_Freed; dvander@283: /* Now, unlink us, so we're not being tracked by the owner */ dvander@283: if (pHandle->owner) dvander@283: { dvander@283: UnlinkHandleFromOwner(pHandle, index); dvander@283: } dvander@283: } dvander@283: } dvander@222: dvander@222: return HandleError_None; dvander@222: } dvander@222: dvander@262: HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) dvander@222: { dvander@222: unsigned int index; dvander@222: QHandle *pHandle; dvander@222: HandleError err; dvander@262: IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; dvander@222: dvander@262: if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) dvander@222: { dvander@222: return err; dvander@222: } dvander@222: dvander@262: if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity)) dvander@259: { dvander@259: return HandleError_Access; dvander@259: } dvander@259: dvander@283: return FreeHandle(pHandle, index); dvander@218: } dvander@218: dvander@262: HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object) dvander@218: { dvander@222: unsigned int index; dvander@222: QHandle *pHandle; dvander@222: HandleError err; dvander@262: IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; dvander@218: dvander@262: if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) dvander@218: { dvander@222: return err; dvander@218: } dvander@218: dvander@262: if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity)) dvander@262: { dvander@262: return HandleError_Access; dvander@262: } dvander@262: dvander@218: /* Check the type inheritance */ dvander@218: if (pHandle->type & HANDLESYS_SUBTYPE_MASK) dvander@218: { dvander@218: if (pHandle->type != type dvander@218: && (TypeParent(pHandle->type) != TypeParent(type))) dvander@218: { dvander@218: return HandleError_Type; dvander@218: } dvander@247: } else if (type) { dvander@218: if (pHandle->type != type) dvander@218: { dvander@218: return HandleError_Type; dvander@218: } dvander@218: } dvander@218: dvander@218: if (object) dvander@218: { dvander@222: /* if we're a clone, the rules change - object is ONLY in our reference */ dvander@222: if (pHandle->clone) dvander@222: { dvander@262: pHandle = &m_Handles[pHandle->clone]; dvander@222: } dvander@218: *object = pHandle->object; dvander@218: } dvander@218: dvander@218: return HandleError_None; dvander@218: } dvander@218: dvander@283: void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index) dvander@283: { dvander@283: /* Unlink us if necessary */ dvander@283: unsigned int ident_index; dvander@283: if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None) dvander@283: { dvander@283: /* Uh-oh! */ dvander@283: assert(pHandle->owner == 0); dvander@283: return; dvander@283: } dvander@283: /* Note that since 0 is an invalid handle, if any of these links are 0, dvander@283: * the data can still be set. dvander@283: */ dvander@283: QHandle *pIdentity = &m_Handles[ident_index]; dvander@283: dvander@283: /* Unlink case: We're the head AND tail node */ dvander@283: if (index == pIdentity->ch_prev && index == pIdentity->ch_next) dvander@283: { dvander@283: pIdentity->ch_prev = 0; dvander@283: pIdentity->ch_next = 0; dvander@283: } dvander@283: /* Unlink case: We're the head node */ dvander@283: else if (index == pIdentity->ch_prev) { dvander@283: /* Link us to the next in the chain */ dvander@283: pIdentity->ch_prev = pHandle->ch_next; dvander@283: /* Patch up the previous link */ dvander@283: m_Handles[pHandle->ch_next].ch_prev = 0; dvander@283: } dvander@283: /* Unlink case: We're the tail node */ dvander@283: else if (index == pIdentity->ch_next) { dvander@283: /* Link us to the previous in the chain */ dvander@283: pIdentity->ch_next = pHandle->ch_prev; dvander@283: /* Patch up the next link */ dvander@283: m_Handles[pHandle->ch_prev].ch_next = 0; dvander@283: } dvander@283: /* Unlink case: We're in the middle! */ dvander@283: else { dvander@283: /* Patch the forward reference */ dvander@283: m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev; dvander@283: /* Patch the backward reference */ dvander@283: m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next; dvander@283: } dvander@283: dvander@283: /* Lastly, decrease the reference count */ dvander@283: pIdentity->refcount--; dvander@283: } dvander@283: dvander@222: void HandleSystem::ReleasePrimHandle(unsigned int index) dvander@222: { dvander@222: QHandle *pHandle = &m_Handles[index]; dvander@283: HandleSet set = pHandle->set; dvander@283: dvander@283: if (pHandle->owner && (set != HandleSet_Identity)) dvander@283: { dvander@283: UnlinkHandleFromOwner(pHandle, index); dvander@283: } dvander@283: dvander@283: /* Were we an identity ourself? */ dvander@283: QHandle *pLocal; dvander@283: if (set == HandleSet_Identity) dvander@283: { dvander@283: /* Extra work to do. We need to find everything connected to this identity and release it. */ dvander@351: unsigned int ch_index; dvander@364: #if defined _DEBUG dvander@364: unsigned int old_index = 0; dvander@364: #endif dvander@283: while ((ch_index = pHandle->ch_next) != 0) dvander@283: { dvander@283: pLocal = &m_Handles[ch_index]; dvander@283: #if defined _DEBUG dvander@283: assert(old_index != ch_index); dvander@283: assert(pLocal->set == HandleSet_Used); dvander@283: old_index = ch_index; dvander@283: #endif dvander@283: FreeHandle(pLocal, ch_index); dvander@283: } dvander@283: } dvander@283: dvander@229: pHandle->set = HandleSet_None; dvander@222: m_Types[pHandle->type].opened--; dvander@222: m_Handles[++m_FreeHandles].freeID = index; dvander@222: } dvander@222: dvander@229: bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) dvander@218: { dvander@218: if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) dvander@218: { dvander@218: return false; dvander@218: } dvander@218: dvander@218: QHandleType *pType = &m_Types[type]; dvander@218: dvander@262: if (pType->typeSec.ident dvander@262: && pType->typeSec.ident != ident) dvander@218: { dvander@218: return false; dvander@218: } dvander@218: dvander@218: if (pType->dispatch == NULL) dvander@218: { dvander@218: return false; dvander@218: } dvander@218: dvander@218: /* Remove children if we have to */ dvander@218: if (!(type & HANDLESYS_SUBTYPE_MASK)) dvander@218: { dvander@218: QHandleType *childType; dvander@218: for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++) dvander@218: { dvander@218: childType = &m_Types[type + i]; dvander@218: if (childType->dispatch) dvander@218: { dvander@262: RemoveType(type + i, childType->typeSec.ident); dvander@218: } dvander@218: } dvander@218: /* Link us into the free chain */ dvander@218: m_Types[++m_FreeTypes].freeID = type; dvander@218: } dvander@218: dvander@218: /* Invalidate the type now */ dvander@218: IHandleTypeDispatch *dispatch = pType->dispatch; dvander@218: pType->dispatch = NULL; dvander@218: dvander@218: /* Make sure nothing is using this type. */ dvander@218: if (pType->opened) dvander@218: { dvander@218: QHandle *pHandle; dvander@297: for (unsigned int i=1; i<=m_HandleTail; i++) dvander@218: { dvander@218: pHandle = &m_Handles[i]; dvander@218: if (!pHandle->set || pHandle->type != type) dvander@218: { dvander@218: continue; dvander@218: } dvander@222: if (pHandle->clone) dvander@222: { dvander@222: /* Get parent */ dvander@222: QHandle *pOther = &m_Handles[pHandle->clone]; dvander@222: if (--pOther->refcount == 0) dvander@222: { dvander@222: /* Free! */ dvander@222: dispatch->OnHandleDestroy(type, pOther->object); dvander@222: ReleasePrimHandle(pHandle->clone); dvander@222: } dvander@222: /* Unlink ourselves since we don't have a reference count */ dvander@222: ReleasePrimHandle(i); dvander@222: } else { dvander@222: /* If it's not a clone, we still have to check the reference count. dvander@222: * Either way, we'll be destroyed eventually because the handle types do not change. dvander@222: */ dvander@222: if (--pHandle->refcount == 0) dvander@222: { dvander@222: /* Free! */ dvander@222: dispatch->OnHandleDestroy(type, pHandle->object); dvander@222: ReleasePrimHandle(i); dvander@222: } dvander@222: } dvander@222: if (pType->opened == 0) dvander@218: { dvander@218: break; dvander@218: } dvander@218: } dvander@218: } dvander@218: dvander@218: return true; dvander@218: } dvander@229: dvander@262: bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) dvander@262: { dvander@262: if (pTypeAccess) dvander@262: { dvander@262: if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) dvander@262: { dvander@262: return false; dvander@262: } dvander@262: pTypeAccess->access[HTypeAccess_Create] = false; dvander@262: pTypeAccess->access[HTypeAccess_Inherit] = false; dvander@262: pTypeAccess->ident = NULL; dvander@262: } dvander@262: dvander@262: if (pHandleAccess) dvander@262: { dvander@262: if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) dvander@262: { dvander@262: return false; dvander@262: } dvander@262: dvander@262: pHandleAccess->access[HandleAccess_Clone] = 0; dvander@262: pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER; dvander@262: pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY; dvander@262: } dvander@262: dvander@262: return true; dvander@262: }