diff -r 5659ebceaa16 -r 8d009d0087f1 core/systems/HandleSys.cpp --- a/core/systems/HandleSys.cpp Sun Dec 17 02:51:35 2006 +0000 +++ b/core/systems/HandleSys.cpp Sun Dec 17 09:56:45 2006 +0000 @@ -1,5 +1,6 @@ #include "HandleSys.h" #include "PluginSys.h" +#include HandleSystem g_HandleSys; @@ -56,7 +57,7 @@ } if (parent >= HANDLESYS_TYPEARRAY_SIZE || m_Types[parent].dispatch != NULL - || m_Types[parent].sec.all.canInherit == false) + || m_Types[parent].sec.access[HandleAccess_Inherit] == false) { return 0; } @@ -68,12 +69,13 @@ { security = &m_Types[parent].sec; } else { - static HandleSecurity def_h = {0, HandleAccess() }; + static HandleSecurity def_h; security = &def_h; } } - if (security->all.canCreate && sm_trie_retrieve(m_TypeLookup, name, NULL)) + if (security->access[HandleAccess_Create] + && sm_trie_retrieve(m_TypeLookup, name, NULL)) { return 0; } @@ -158,6 +160,54 @@ return true; } +HandleError HandleSystem::MakePrimHandle(HandleType_t type, + QHandle **in_pHandle, + unsigned int *in_index, + Handle_t *in_handle) +{ + unsigned int handle; + if (m_FreeHandles == 0) + { + if (m_HandleTail >= HANDLESYS_MAX_HANDLES) + { + return HandleError_Limit;; + } + handle = ++m_HandleTail; + } else { + handle = m_Handles[m_FreeHandles--].freeID; + } + + QHandle *pHandle = &m_Handles[handle]; + + assert(pHandle->set == false); + + if (++m_HSerial >= HANDLESYS_MAX_SERIALS) + { + m_HSerial = 1; + } + + /* Set essential information */ + pHandle->set = true; + pHandle->refcount = 1; + pHandle->type = type; + pHandle->serial = m_HSerial; + + /* Create the hash value */ + Handle_t hash = pHandle->serial; + hash <<= 16; + hash |= handle; + + /* Add a reference count to the type */ + m_Types[type].opened++; + + /* Output */ + *in_pHandle = pHandle; + *in_index = handle; + *in_handle = hash; + + return HandleError_None; +} + Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident) { if (!type @@ -169,44 +219,27 @@ /* Check the security of this handle */ QHandleType *pType = &m_Types[type]; - if (!pType->sec.all.canCreate + if (!pType->sec.access[HandleAccess_Create] && pType->sec.owner != ident) { return 0; } - unsigned int handle = 0; - if (m_FreeHandles == 0) + unsigned int index; + Handle_t handle; + QHandle *pHandle; + HandleError err; + + if ((err=MakePrimHandle(type, &pHandle, &index, &handle)) != HandleError_None) { - if (m_HandleTail >= HANDLESYS_MAX_HANDLES) - { - return 0; - } - handle = ++m_HandleTail; - } else { - handle = m_Handles[m_FreeHandles--].freeID; + return 0; } - QHandle *pHandle = &m_Handles[handle]; - - pHandle->type = type; pHandle->source = source; - pHandle->set = true; pHandle->object = object; + pHandle->clone = 0; - if (++m_HSerial >= HANDLESYS_MAX_SERIALS) - { - m_HSerial = 1; - } - pHandle->serial = m_HSerial; - - Handle_t hash = pHandle->serial; - hash <<= 16; - hash |= handle; - - pType->opened++; - - return hash; + return handle; } Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, @@ -219,7 +252,11 @@ return CreateHandle(type, object, pPlugin->GetIdentity(), ident); } -HandleError HandleSystem::DestroyHandle(Handle_t handle, IdentityToken_t ident) +HandleError HandleSystem::GetHandle(Handle_t handle, + IdentityToken_t ident, + QHandle **in_pHandle, + unsigned int *in_index, + HandleAccessRight access) { unsigned int serial = (handle >> 16); unsigned int index = (handle & HANDLESYS_HANDLE_MASK); @@ -232,8 +269,8 @@ QHandle *pHandle = &m_Handles[index]; QHandleType *pType = &m_Types[pHandle->type]; - if (!pType->sec.all.canDelete - && pType->sec.owner != ident) + if ((access != HandleAccess_TOTAL) + && (!pType->sec.access[access] && pType->sec.owner != ident)) { return HandleError_Access; } @@ -246,10 +283,80 @@ return HandleError_Changed; } - pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); - pType->opened--; - pHandle->set = false; - m_Handles[++m_FreeTypes].freeID = index; + *in_pHandle = pHandle; + *in_index = index; + + return HandleError_None; +} + +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t source, IdentityToken_t ident) +{ + HandleError err; + QHandle *pHandle; + unsigned int index; + + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Clone)) != HandleError_None) + { + return err; + } + + QHandleType *pType = &m_Types[pHandle->type]; + + /* Get a new Handle ID */ + unsigned int new_index; + QHandle *pNewHandle; + Handle_t new_handle; + + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle)) != HandleError_None) + { + return err; + } + + pNewHandle->clone = index; + pNewHandle->source = source; + + if (out_newhandle) + { + *out_newhandle = new_handle; + } + + return HandleError_None; +} + +HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t ident) +{ + unsigned int index; + QHandle *pHandle; + HandleError err; + + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Delete)) != HandleError_None) + { + return err; + } + + QHandleType *pType = &m_Types[pHandle->type]; + + bool dofree = false; + if (pHandle->clone) + { + /* If we're a clone, there's not a lot to do. */ + if (FreeHandle(pHandle->clone, ident) != HandleError_None) + { + assert(false); + } + dofree = true; + } else { + if (--pHandle->refcount == 0) + { + dofree = true; + pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); + } + } + + if (dofree) + { + ReleasePrimHandle(index); + } return HandleError_None; } @@ -264,24 +371,13 @@ IdentityToken_t ident, void **object) { - unsigned int serial = (handle >> 16); - unsigned int index = (handle & HANDLESYS_HANDLE_MASK); - - if (index == 0 || index == 0xFFFF) - { - return HandleError_Index; - } + unsigned int index; + QHandle *pHandle; + HandleError err; - QHandle *pHandle = &m_Handles[index]; - - /* Do sanity checks first */ - if (!pHandle->set) + if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Read)) != HandleError_None) { - return HandleError_Freed; - } - if (pHandle->serial != serial) - { - return HandleError_Changed; + return err; } /* Check the type inheritance */ @@ -299,22 +395,28 @@ } } - /* Now do security checks */ - QHandleType *pType = &m_Types[pHandle->type]; - if (!pType->sec.all.canRead - && pType->sec.owner != ident) - { - return HandleError_Access; - } - if (object) { + /* if we're a clone, the rules change - object is ONLY in our reference */ + if (pHandle->clone) + { + pHandle = &m_Handles[pHandle->clone]; + } *object = pHandle->object; } return HandleError_None; } +void HandleSystem::ReleasePrimHandle(unsigned int index) +{ + QHandle *pHandle = &m_Handles[index]; + + pHandle->set = false; + m_Types[pHandle->type].opened--; + m_Handles[++m_FreeHandles].freeID = index; +} + bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) { if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) @@ -358,17 +460,37 @@ if (pType->opened) { QHandle *pHandle; - for (unsigned int i=1; i<=HANDLESYS_MAX_HANDLES; i++) + for (unsigned int i=1; iset || pHandle->type != type) { continue; } - dispatch->OnHandleDestroy(type, pHandle->object); - pHandle->set = false; - m_Handles[++m_FreeHandles].freeID = i; - if (--pType->opened == 0) + if (pHandle->clone) + { + /* Get parent */ + QHandle *pOther = &m_Handles[pHandle->clone]; + if (--pOther->refcount == 0) + { + /* Free! */ + dispatch->OnHandleDestroy(type, pOther->object); + ReleasePrimHandle(pHandle->clone); + } + /* Unlink ourselves since we don't have a reference count */ + ReleasePrimHandle(i); + } else { + /* If it's not a clone, we still have to check the reference count. + * Either way, we'll be destroyed eventually because the handle types do not change. + */ + if (--pHandle->refcount == 0) + { + /* Free! */ + dispatch->OnHandleDestroy(type, pHandle->object); + ReleasePrimHandle(i); + } + } + if (pType->opened == 0) { break; }