1.1 --- a/core/systems/HandleSys.cpp Fri Mar 28 06:21:34 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1052 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include "HandleSys.h"
1.36 -#include "ShareSys.h"
1.37 -#include "PluginSys.h"
1.38 -#include "ExtensionSys.h"
1.39 -#include "Logger.h"
1.40 -#include <assert.h>
1.41 -#include <string.h>
1.42 -
1.43 -HandleSystem g_HandleSys;
1.44 -
1.45 -QHandle *ignore_handle;
1.46 -
1.47 -inline HandleType_t TypeParent(HandleType_t type)
1.48 -{
1.49 - return (type & ~HANDLESYS_SUBTYPE_MASK);
1.50 -}
1.51 -
1.52 -inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
1.53 -{
1.54 - return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
1.55 -}
1.56 -
1.57 -HandleSystem::HandleSystem()
1.58 -{
1.59 - m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
1.60 - memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
1.61 -
1.62 - m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
1.63 - memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
1.64 -
1.65 - m_TypeLookup = sm_trie_create();
1.66 - m_strtab = new BaseStringTable(512);
1.67 -
1.68 - m_TypeTail = 0;
1.69 -}
1.70 -
1.71 -HandleSystem::~HandleSystem()
1.72 -{
1.73 - delete [] m_Handles;
1.74 - delete [] m_Types;
1.75 - sm_trie_destroy(m_TypeLookup);
1.76 - delete m_strtab;
1.77 -}
1.78 -
1.79 -
1.80 -HandleType_t HandleSystem::CreateType(const char *name,
1.81 - IHandleTypeDispatch *dispatch,
1.82 - HandleType_t parent,
1.83 - const TypeAccess *typeAccess,
1.84 - const HandleAccess *hndlAccess,
1.85 - IdentityToken_t *ident,
1.86 - HandleError *err)
1.87 -{
1.88 - if (!dispatch)
1.89 - {
1.90 - if (err)
1.91 - {
1.92 - *err = HandleError_Parameter;
1.93 - }
1.94 - return 0;
1.95 - }
1.96 -
1.97 - if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.98 - {
1.99 - if (err)
1.100 - {
1.101 - *err = HandleError_Version;
1.102 - }
1.103 - return 0;
1.104 - }
1.105 -
1.106 - if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.107 - {
1.108 - if (err)
1.109 - {
1.110 - *err = HandleError_Version;
1.111 - }
1.112 - return 0;
1.113 - }
1.114 -
1.115 - bool isChild = false;
1.116 -
1.117 - if (parent != 0)
1.118 - {
1.119 - isChild = true;
1.120 - if (parent & HANDLESYS_SUBTYPE_MASK)
1.121 - {
1.122 - if (err)
1.123 - {
1.124 - *err = HandleError_NoInherit;
1.125 - }
1.126 - return 0;
1.127 - }
1.128 - if (parent >= HANDLESYS_TYPEARRAY_SIZE
1.129 - || m_Types[parent].dispatch == NULL)
1.130 - {
1.131 - if (err)
1.132 - {
1.133 - *err = HandleError_Parameter;
1.134 - }
1.135 - return 0;
1.136 - }
1.137 - if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
1.138 - && (m_Types[parent].typeSec.ident != ident))
1.139 - {
1.140 - if (err)
1.141 - {
1.142 - *err = HandleError_Access;
1.143 - }
1.144 - return 0;
1.145 - }
1.146 - }
1.147 -
1.148 - if (name && name[0] != '\0')
1.149 - {
1.150 - if (sm_trie_retrieve(m_TypeLookup, name, NULL))
1.151 - {
1.152 - if (err)
1.153 - {
1.154 - *err = HandleError_Parameter;
1.155 - }
1.156 - return 0;
1.157 - }
1.158 - }
1.159 -
1.160 - unsigned int index;
1.161 -
1.162 - if (isChild)
1.163 - {
1.164 - QHandleType *pParent = &m_Types[parent];
1.165 - if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
1.166 - {
1.167 - if (err)
1.168 - {
1.169 - *err = HandleError_Limit;
1.170 - }
1.171 - return 0;
1.172 - }
1.173 - index = 0;
1.174 - for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
1.175 - {
1.176 - if (m_Types[parent + i].dispatch == NULL)
1.177 - {
1.178 - index = parent + i;
1.179 - break;
1.180 - }
1.181 - }
1.182 - if (!index)
1.183 - {
1.184 - if (err)
1.185 - {
1.186 - *err = HandleError_Limit;
1.187 - }
1.188 - return 0;
1.189 - }
1.190 - pParent->children++;
1.191 - } else {
1.192 - if (m_FreeTypes == 0)
1.193 - {
1.194 - /* Reserve another index */
1.195 - if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
1.196 - {
1.197 - if (err)
1.198 - {
1.199 - *err = HandleError_Limit;
1.200 - }
1.201 - return 0;
1.202 - } else {
1.203 - m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
1.204 - index = m_TypeTail;
1.205 - }
1.206 - } else {
1.207 - /* The "free array" is compacted into the normal array for easiness */
1.208 - index = m_Types[m_FreeTypes--].freeID;
1.209 - }
1.210 - }
1.211 -
1.212 - QHandleType *pType = &m_Types[index];
1.213 -
1.214 - pType->dispatch = dispatch;
1.215 - if (name && name[0] != '\0')
1.216 - {
1.217 - pType->nameIdx = m_strtab->AddString(name);
1.218 - sm_trie_insert(m_TypeLookup, name, (void *)pType);
1.219 - } else {
1.220 - pType->nameIdx = -1;
1.221 - }
1.222 -
1.223 - pType->opened = 0;
1.224 -
1.225 - if (typeAccess)
1.226 - {
1.227 - pType->typeSec = *typeAccess;
1.228 - } else {
1.229 - InitAccessDefaults(&pType->typeSec, NULL);
1.230 - pType->typeSec.ident = ident;
1.231 - }
1.232 -
1.233 - if (hndlAccess)
1.234 - {
1.235 - pType->hndlSec = *hndlAccess;
1.236 - } else {
1.237 - InitAccessDefaults(NULL, &pType->hndlSec);
1.238 - }
1.239 -
1.240 - if (!isChild)
1.241 - {
1.242 - pType->children = 0;
1.243 - }
1.244 -
1.245 - return index;
1.246 -}
1.247 -
1.248 -bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
1.249 -{
1.250 - QHandleType *_type;
1.251 -
1.252 - if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
1.253 - {
1.254 - return false;
1.255 - }
1.256 -
1.257 - unsigned int offset = _type - m_Types;
1.258 -
1.259 - if (type)
1.260 - {
1.261 - *type = offset;
1.262 - }
1.263 -
1.264 - return true;
1.265 -}
1.266 -
1.267 -HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
1.268 -{
1.269 - if (m_FreeHandles == 0)
1.270 - {
1.271 - if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
1.272 - {
1.273 - return HandleError_Limit;;
1.274 - }
1.275 - *handle = ++m_HandleTail;
1.276 - }
1.277 - else
1.278 - {
1.279 - *handle = m_Handles[m_FreeHandles--].freeID;
1.280 - }
1.281 -
1.282 - return HandleError_None;
1.283 -}
1.284 -
1.285 -HandleError HandleSystem::MakePrimHandle(HandleType_t type,
1.286 - QHandle **in_pHandle,
1.287 - unsigned int *in_index,
1.288 - Handle_t *in_handle,
1.289 - IdentityToken_t *owner,
1.290 - bool identity)
1.291 -{
1.292 - HandleError err;
1.293 - unsigned int owner_index = 0;
1.294 -
1.295 - if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
1.296 - {
1.297 - return HandleError_Identity;
1.298 - }
1.299 -
1.300 - unsigned int handle;
1.301 - if ((err = TryAllocHandle(&handle)) != HandleError_None)
1.302 - {
1.303 - if (!TryAndFreeSomeHandles()
1.304 - || (err = TryAllocHandle(&handle)) != HandleError_None)
1.305 - {
1.306 - return err;
1.307 - }
1.308 - }
1.309 -
1.310 - QHandle *pHandle = &m_Handles[handle];
1.311 -
1.312 - assert(pHandle->set == false);
1.313 -
1.314 - if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
1.315 - {
1.316 - m_HSerial = 1;
1.317 - }
1.318 -
1.319 - /* Set essential information */
1.320 - pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
1.321 - pHandle->refcount = 1;
1.322 - pHandle->type = type;
1.323 - pHandle->serial = m_HSerial;
1.324 - pHandle->owner = owner;
1.325 - pHandle->ch_next = 0;
1.326 - pHandle->access_special = false;
1.327 - pHandle->is_destroying = false;
1.328 -
1.329 - /* Create the hash value */
1.330 - Handle_t hash = pHandle->serial;
1.331 - hash <<= 16;
1.332 - hash |= handle;
1.333 -
1.334 - /* Add a reference count to the type */
1.335 - m_Types[type].opened++;
1.336 -
1.337 - /* Output */
1.338 - *in_pHandle = pHandle;
1.339 - *in_index = handle;
1.340 - *in_handle = hash;
1.341 -
1.342 - /* Decode the identity token
1.343 - * For now, we don't allow nested ownership
1.344 - */
1.345 - if (owner && !identity)
1.346 - {
1.347 - QHandle *pIdentity = &m_Handles[owner_index];
1.348 - if (pIdentity->ch_prev == 0)
1.349 - {
1.350 - pIdentity->ch_prev = handle;
1.351 - pIdentity->ch_next = handle;
1.352 - pHandle->ch_prev = 0;
1.353 - }
1.354 - else
1.355 - {
1.356 - /* Link previous node to us (forward) */
1.357 - m_Handles[pIdentity->ch_next].ch_next = handle;
1.358 - /* Link us to previous node (backwards) */
1.359 - pHandle->ch_prev = pIdentity->ch_next;
1.360 - /* Set new tail */
1.361 - pIdentity->ch_next = handle;
1.362 - }
1.363 - pIdentity->refcount++;
1.364 - }
1.365 - else
1.366 - {
1.367 - pHandle->ch_prev = 0;
1.368 - }
1.369 -
1.370 - return HandleError_None;
1.371 -}
1.372 -
1.373 -void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
1.374 -{
1.375 - if (!type
1.376 - || type >= HANDLESYS_TYPEARRAY_SIZE
1.377 - || m_Types[type].dispatch == NULL)
1.378 - {
1.379 - return;
1.380 - }
1.381 -
1.382 - m_Types[type].typeSec.ident = pToken;
1.383 -}
1.384 -
1.385 -Handle_t HandleSystem::CreateHandleInt(HandleType_t type,
1.386 - void *object,
1.387 - const HandleSecurity *pSec,
1.388 - HandleError *err,
1.389 - const HandleAccess *pAccess,
1.390 - bool identity)
1.391 -{
1.392 - IdentityToken_t *ident;
1.393 - IdentityToken_t *owner;
1.394 -
1.395 - if (pSec)
1.396 - {
1.397 - ident = pSec->pIdentity;
1.398 - owner = pSec->pOwner;
1.399 - } else {
1.400 - ident = NULL;
1.401 - owner = NULL;
1.402 - }
1.403 -
1.404 - if (!type
1.405 - || type >= HANDLESYS_TYPEARRAY_SIZE
1.406 - || m_Types[type].dispatch == NULL)
1.407 - {
1.408 - if (err)
1.409 - {
1.410 - *err = HandleError_Parameter;
1.411 - }
1.412 - return 0;
1.413 - }
1.414 -
1.415 - /* Check to see if we're allowed to create this handle type */
1.416 - QHandleType *pType = &m_Types[type];
1.417 - if (!pType->typeSec.access[HTypeAccess_Create]
1.418 - && (!pType->typeSec.ident
1.419 - || pType->typeSec.ident != ident))
1.420 - {
1.421 - if (err)
1.422 - {
1.423 - *err = HandleError_Access;
1.424 - }
1.425 - return 0;
1.426 - }
1.427 -
1.428 - unsigned int index;
1.429 - Handle_t handle;
1.430 - QHandle *pHandle;
1.431 - HandleError _err;
1.432 -
1.433 - if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
1.434 - {
1.435 - if (err)
1.436 - {
1.437 - *err = _err;
1.438 - }
1.439 - return 0;
1.440 - }
1.441 -
1.442 - if (pAccess)
1.443 - {
1.444 - pHandle->access_special = true;
1.445 - pHandle->sec = *pAccess;
1.446 - }
1.447 -
1.448 - pHandle->object = object;
1.449 - pHandle->clone = 0;
1.450 -
1.451 - return handle;
1.452 -}
1.453 -
1.454 -Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
1.455 -{
1.456 - return CreateHandleInt(type, object, pSec, err, pAccess, false);
1.457 -}
1.458 -
1.459 -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
1.460 -{
1.461 - HandleSecurity sec;
1.462 -
1.463 - sec.pIdentity = ident;
1.464 - sec.pOwner = owner;
1.465 -
1.466 - return CreateHandleEx(type, object, &sec, NULL, err);
1.467 -}
1.468 -
1.469 -bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
1.470 -{
1.471 - /* Check the type inheritance */
1.472 - if (intype & HANDLESYS_SUBTYPE_MASK)
1.473 - {
1.474 - if (intype != outtype
1.475 - && (TypeParent(intype) != TypeParent(outtype)))
1.476 - {
1.477 - return false;
1.478 - }
1.479 - } else {
1.480 - if (intype != outtype)
1.481 - {
1.482 - return false;
1.483 - }
1.484 - }
1.485 -
1.486 - return true;
1.487 -}
1.488 -
1.489 -HandleError HandleSystem::GetHandle(Handle_t handle,
1.490 - IdentityToken_t *ident,
1.491 - QHandle **in_pHandle,
1.492 - unsigned int *in_index,
1.493 - bool ignoreFree)
1.494 -{
1.495 - unsigned int serial = (handle >> 16);
1.496 - unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
1.497 -
1.498 - if (index == 0 || index == 0xFFFF)
1.499 - {
1.500 - return HandleError_Index;
1.501 - }
1.502 -
1.503 - QHandle *pHandle = &m_Handles[index];
1.504 -
1.505 - if (!pHandle->set
1.506 - || (pHandle->set == HandleSet_Freed && !ignoreFree))
1.507 - {
1.508 - return HandleError_Freed;
1.509 - } else if (pHandle->set == HandleSet_Identity
1.510 - && ident != g_ShareSys.GetIdentRoot())
1.511 - {
1.512 - /* Only IdentityHandle() can read this! */
1.513 - return HandleError_Identity;
1.514 - }
1.515 - if (pHandle->serial != serial)
1.516 - {
1.517 - return HandleError_Changed;
1.518 - }
1.519 -
1.520 - *in_pHandle = pHandle;
1.521 - *in_index = index;
1.522 -
1.523 - return HandleError_None;
1.524 -}
1.525 -
1.526 -bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
1.527 -{
1.528 - QHandleType *pType = &m_Types[pHandle->type];
1.529 - unsigned int access;
1.530 -
1.531 - if (pHandle->access_special)
1.532 - {
1.533 - access = pHandle->sec.access[right];
1.534 - } else {
1.535 - access = pType->hndlSec.access[right];
1.536 - }
1.537 -
1.538 - /* Check if the type's identity matches */
1.539 - if (access & HANDLE_RESTRICT_IDENTITY)
1.540 - {
1.541 - IdentityToken_t *owner = pType->typeSec.ident;
1.542 - if (!owner
1.543 - || (!pSecurity || pSecurity->pIdentity != owner))
1.544 - {
1.545 - return false;
1.546 - }
1.547 - }
1.548 -
1.549 - /* Check if the owner is allowed */
1.550 - if (access & HANDLE_RESTRICT_OWNER)
1.551 - {
1.552 - IdentityToken_t *owner = pHandle->owner;
1.553 - if (owner
1.554 - && (!pSecurity || pSecurity->pOwner != owner))
1.555 - {
1.556 - return false;
1.557 - }
1.558 - }
1.559 -
1.560 - return true;
1.561 -}
1.562 -
1.563 -HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
1.564 -{
1.565 - /* Get a new Handle ID */
1.566 - unsigned int new_index;
1.567 - QHandle *pNewHandle;
1.568 - Handle_t new_handle;
1.569 - HandleError err;
1.570 -
1.571 - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
1.572 - {
1.573 - return err;
1.574 - }
1.575 -
1.576 - /* Assign permissions from parent */
1.577 - if (pHandle->access_special)
1.578 - {
1.579 - pNewHandle->access_special = true;
1.580 - pNewHandle->sec = pHandle->sec;
1.581 - }
1.582 -
1.583 - pNewHandle->clone = index;
1.584 - pHandle->refcount++;
1.585 -
1.586 - *newhandle = new_handle;
1.587 -
1.588 - return HandleError_None;
1.589 -}
1.590 -
1.591 -HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
1.592 -{
1.593 - HandleError err;
1.594 - QHandle *pHandle;
1.595 - unsigned int index;
1.596 - IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
1.597 -
1.598 - if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
1.599 - {
1.600 - return err;
1.601 - }
1.602 -
1.603 - /* Identities cannot be cloned */
1.604 - if (pHandle->set == HandleSet_Identity)
1.605 - {
1.606 - return HandleError_Identity;
1.607 - }
1.608 -
1.609 - /* Check if the handle can be cloned */
1.610 - if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
1.611 - {
1.612 - return HandleError_Access;
1.613 - }
1.614 -
1.615 - /* Make sure we're not cloning a clone */
1.616 - if (pHandle->clone)
1.617 - {
1.618 - QHandle *pParent = &m_Handles[pHandle->clone];
1.619 - return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
1.620 - }
1.621 -
1.622 - return CloneHandle(pHandle, index, newhandle, newOwner);
1.623 -}
1.624 -
1.625 -HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
1.626 -{
1.627 - QHandleType *pType = &m_Types[pHandle->type];
1.628 -
1.629 - if (pHandle->clone)
1.630 - {
1.631 - /* If we're a clone, decrease the parent reference count */
1.632 - QHandle *pMaster;
1.633 - unsigned int master;
1.634 -
1.635 - /* Note that if we ever have per-handle security, we would need to re-check
1.636 - * the access on this Handle. */
1.637 - master = pHandle->clone;
1.638 - pMaster = &m_Handles[master];
1.639 -
1.640 - /* Release the clone now */
1.641 - ReleasePrimHandle(index);
1.642 -
1.643 - /* Decrement the master's reference count */
1.644 - if (--pMaster->refcount == 0)
1.645 - {
1.646 - /* Type should be the same but do this anyway... */
1.647 - pType = &m_Types[pMaster->type];
1.648 - pMaster->is_destroying = true;
1.649 - pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
1.650 - ReleasePrimHandle(master);
1.651 - }
1.652 - } else if (pHandle->set == HandleSet_Identity) {
1.653 - /* If we're an identity, skip all this stuff!
1.654 - * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
1.655 - */
1.656 - ReleasePrimHandle(index);
1.657 - } else {
1.658 - /* Decrement, free if necessary */
1.659 - if (--pHandle->refcount == 0)
1.660 - {
1.661 - pHandle->is_destroying = true;
1.662 - pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
1.663 - ReleasePrimHandle(index);
1.664 - } else {
1.665 - /* We must be cloned, so mark ourselves as freed */
1.666 - pHandle->set = HandleSet_Freed;
1.667 - /* Now, unlink us, so we're not being tracked by the owner */
1.668 - if (pHandle->owner)
1.669 - {
1.670 - UnlinkHandleFromOwner(pHandle, index);
1.671 - }
1.672 - }
1.673 - }
1.674 -
1.675 - return HandleError_None;
1.676 -}
1.677 -
1.678 -HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
1.679 -{
1.680 - unsigned int index;
1.681 - QHandle *pHandle;
1.682 - HandleError err;
1.683 - IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
1.684 -
1.685 - if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
1.686 - {
1.687 - return err;
1.688 - }
1.689 -
1.690 - if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
1.691 - {
1.692 - return HandleError_Access;
1.693 - }
1.694 -
1.695 - if (pHandle->is_destroying)
1.696 - {
1.697 - /* Someone tried to free this recursively.
1.698 - * We'll just ignore this safely.
1.699 - */
1.700 - return HandleError_None;
1.701 - }
1.702 -
1.703 - return FreeHandle(pHandle, index);
1.704 -}
1.705 -
1.706 -HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
1.707 -{
1.708 - unsigned int index;
1.709 - QHandle *pHandle;
1.710 - HandleError err;
1.711 - IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
1.712 -
1.713 - if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
1.714 - {
1.715 - return err;
1.716 - }
1.717 -
1.718 - if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
1.719 - {
1.720 - return HandleError_Access;
1.721 - }
1.722 -
1.723 - /* Check the type inheritance */
1.724 - if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
1.725 - {
1.726 - if (pHandle->type != type
1.727 - && (TypeParent(pHandle->type) != TypeParent(type)))
1.728 - {
1.729 - return HandleError_Type;
1.730 - }
1.731 - } else if (type) {
1.732 - if (pHandle->type != type)
1.733 - {
1.734 - return HandleError_Type;
1.735 - }
1.736 - }
1.737 -
1.738 - if (object)
1.739 - {
1.740 - /* if we're a clone, the rules change - object is ONLY in our reference */
1.741 - if (pHandle->clone)
1.742 - {
1.743 - pHandle = &m_Handles[pHandle->clone];
1.744 - }
1.745 - *object = pHandle->object;
1.746 - }
1.747 -
1.748 - return HandleError_None;
1.749 -}
1.750 -
1.751 -void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
1.752 -{
1.753 - /* Unlink us if necessary */
1.754 - unsigned int ident_index;
1.755 - if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
1.756 - {
1.757 - /* Uh-oh! */
1.758 - assert(pHandle->owner == 0);
1.759 - return;
1.760 - }
1.761 - /* Note that since 0 is an invalid handle, if any of these links are 0,
1.762 - * the data can still be set.
1.763 - */
1.764 - QHandle *pIdentity = &m_Handles[ident_index];
1.765 -
1.766 - /* Unlink case: We're the head AND tail node */
1.767 - if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
1.768 - {
1.769 - pIdentity->ch_prev = 0;
1.770 - pIdentity->ch_next = 0;
1.771 - }
1.772 - /* Unlink case: We're the head node */
1.773 - else if (index == pIdentity->ch_prev) {
1.774 - /* Link us to the next in the chain */
1.775 - pIdentity->ch_prev = pHandle->ch_next;
1.776 - /* Patch up the previous link */
1.777 - m_Handles[pHandle->ch_next].ch_prev = 0;
1.778 - }
1.779 - /* Unlink case: We're the tail node */
1.780 - else if (index == pIdentity->ch_next) {
1.781 - /* Link us to the previous in the chain */
1.782 - pIdentity->ch_next = pHandle->ch_prev;
1.783 - /* Patch up the next link */
1.784 - m_Handles[pHandle->ch_prev].ch_next = 0;
1.785 - }
1.786 - /* Unlink case: We're in the middle! */
1.787 - else {
1.788 - /* Patch the forward reference */
1.789 - m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
1.790 - /* Patch the backward reference */
1.791 - m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
1.792 - }
1.793 -
1.794 - /* Lastly, decrease the reference count */
1.795 - pIdentity->refcount--;
1.796 -}
1.797 -
1.798 -void HandleSystem::ReleasePrimHandle(unsigned int index)
1.799 -{
1.800 - QHandle *pHandle = &m_Handles[index];
1.801 - HandleSet set = pHandle->set;
1.802 -
1.803 - if (pHandle->owner && (set != HandleSet_Identity))
1.804 - {
1.805 - UnlinkHandleFromOwner(pHandle, index);
1.806 - }
1.807 -
1.808 - /* Were we an identity ourself? */
1.809 - QHandle *pLocal;
1.810 - if (set == HandleSet_Identity)
1.811 - {
1.812 - /* Extra work to do. We need to find everything connected to this identity and release it. */
1.813 - unsigned int ch_index;
1.814 -#if defined _DEBUG
1.815 - unsigned int old_index = 0;
1.816 -#endif
1.817 - while ((ch_index = pHandle->ch_next) != 0)
1.818 - {
1.819 - pLocal = &m_Handles[ch_index];
1.820 -#if defined _DEBUG
1.821 - assert(old_index != ch_index);
1.822 - assert(pLocal->set == HandleSet_Used);
1.823 - old_index = ch_index;
1.824 -#endif
1.825 - FreeHandle(pLocal, ch_index);
1.826 - }
1.827 - }
1.828 -
1.829 - pHandle->set = HandleSet_None;
1.830 - m_Types[pHandle->type].opened--;
1.831 - m_Handles[++m_FreeHandles].freeID = index;
1.832 -}
1.833 -
1.834 -bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
1.835 -{
1.836 - if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
1.837 - {
1.838 - return false;
1.839 - }
1.840 -
1.841 - QHandleType *pType = &m_Types[type];
1.842 -
1.843 - if (pType->typeSec.ident
1.844 - && pType->typeSec.ident != ident)
1.845 - {
1.846 - return false;
1.847 - }
1.848 -
1.849 - if (pType->dispatch == NULL)
1.850 - {
1.851 - return false;
1.852 - }
1.853 -
1.854 - /* Remove children if we have to */
1.855 - if (!(type & HANDLESYS_SUBTYPE_MASK))
1.856 - {
1.857 - QHandleType *childType;
1.858 - for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
1.859 - {
1.860 - childType = &m_Types[type + i];
1.861 - if (childType->dispatch)
1.862 - {
1.863 - RemoveType(type + i, childType->typeSec.ident);
1.864 - }
1.865 - }
1.866 - /* Link us into the free chain */
1.867 - m_Types[++m_FreeTypes].freeID = type;
1.868 - }
1.869 -
1.870 - /* Invalidate the type now */
1.871 - IHandleTypeDispatch *dispatch = pType->dispatch;
1.872 - pType->dispatch = NULL;
1.873 -
1.874 - /* Make sure nothing is using this type. */
1.875 - if (pType->opened)
1.876 - {
1.877 - QHandle *pHandle;
1.878 - for (unsigned int i=1; i<=m_HandleTail; i++)
1.879 - {
1.880 - pHandle = &m_Handles[i];
1.881 - if (!pHandle->set || pHandle->type != type)
1.882 - {
1.883 - continue;
1.884 - }
1.885 - if (pHandle->clone)
1.886 - {
1.887 - /* Get parent */
1.888 - QHandle *pOther = &m_Handles[pHandle->clone];
1.889 - if (--pOther->refcount == 0)
1.890 - {
1.891 - /* Free! */
1.892 - dispatch->OnHandleDestroy(type, pOther->object);
1.893 - ReleasePrimHandle(pHandle->clone);
1.894 - }
1.895 - /* Unlink ourselves since we don't have a reference count */
1.896 - ReleasePrimHandle(i);
1.897 - } else {
1.898 - /* If it's not a clone, we still have to check the reference count.
1.899 - * Either way, we'll be destroyed eventually because the handle types do not change.
1.900 - */
1.901 - if (--pHandle->refcount == 0)
1.902 - {
1.903 - /* Free! */
1.904 - dispatch->OnHandleDestroy(type, pHandle->object);
1.905 - ReleasePrimHandle(i);
1.906 - }
1.907 - }
1.908 - if (pType->opened == 0)
1.909 - {
1.910 - break;
1.911 - }
1.912 - }
1.913 - }
1.914 -
1.915 - return true;
1.916 -}
1.917 -
1.918 -bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
1.919 -{
1.920 - if (pTypeAccess)
1.921 - {
1.922 - if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.923 - {
1.924 - return false;
1.925 - }
1.926 - pTypeAccess->access[HTypeAccess_Create] = false;
1.927 - pTypeAccess->access[HTypeAccess_Inherit] = false;
1.928 - pTypeAccess->ident = NULL;
1.929 - }
1.930 -
1.931 - if (pHandleAccess)
1.932 - {
1.933 - if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
1.934 - {
1.935 - return false;
1.936 - }
1.937 -
1.938 - pHandleAccess->access[HandleAccess_Clone] = 0;
1.939 - pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
1.940 - pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
1.941 - }
1.942 -
1.943 - return true;
1.944 -}
1.945 -
1.946 -bool HandleSystem::TryAndFreeSomeHandles()
1.947 -{
1.948 - IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
1.949 - IPlugin *highest_owner = NULL;
1.950 - unsigned int highest_handle_count = 0;
1.951 -
1.952 - /* Search all plugins */
1.953 - while (pl_iter->MorePlugins())
1.954 - {
1.955 - IPlugin *plugin = pl_iter->GetPlugin();
1.956 - IdentityToken_t *identity = plugin->GetIdentity();
1.957 - unsigned int handle_count = 0;
1.958 -
1.959 - if (identity == NULL)
1.960 - {
1.961 - continue;
1.962 - }
1.963 -
1.964 - /* Search all handles */
1.965 - for (unsigned int i = 1; i <= m_HandleTail; i++)
1.966 - {
1.967 - if (m_Handles[i].set != HandleSet_Used)
1.968 - {
1.969 - continue;
1.970 - }
1.971 - if (m_Handles[i].owner == identity)
1.972 - {
1.973 - handle_count++;
1.974 - }
1.975 - }
1.976 -
1.977 - if (handle_count > highest_handle_count)
1.978 - {
1.979 - highest_owner = plugin;
1.980 - highest_handle_count = handle_count;
1.981 - }
1.982 -
1.983 - pl_iter->NextPlugin();
1.984 - }
1.985 -
1.986 - if (highest_owner == NULL || highest_handle_count == 0)
1.987 - {
1.988 - return false;
1.989 - }
1.990 -
1.991 - g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
1.992 - g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
1.993 - g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
1.994 -
1.995 - highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS;
1.996 -
1.997 - return g_PluginSys.UnloadPlugin(highest_owner);
1.998 -}
1.999 -
1.1000 -void HandleSystem::Dump(HANDLE_REPORTER rep)
1.1001 -{
1.1002 - rep("%-10.10s\t%-20.20s\t%-20.20s", "Handle", "Owner", "Type");
1.1003 - rep("---------------------------------------------");
1.1004 - for (unsigned int i = 1; i <= m_HandleTail; i++)
1.1005 - {
1.1006 - if (m_Handles[i].set != HandleSet_Used)
1.1007 - {
1.1008 - continue;
1.1009 - }
1.1010 - /* Get the index */
1.1011 - unsigned int index = (m_Handles[i].serial << 16) | i;
1.1012 - /* Determine the owner */
1.1013 - const char *owner = "UNKNOWN";
1.1014 - if (m_Handles[i].owner)
1.1015 - {
1.1016 - IdentityToken_t *pOwner = m_Handles[i].owner;
1.1017 - if (pOwner == g_pCoreIdent)
1.1018 - {
1.1019 - owner = "CORE";
1.1020 - }
1.1021 - else if (pOwner == g_PluginSys.GetIdentity())
1.1022 - {
1.1023 - owner = "PLUGINSYS";
1.1024 - }
1.1025 - else
1.1026 - {
1.1027 - CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
1.1028 - if (ext)
1.1029 - {
1.1030 - owner = ext->GetFilename();
1.1031 - }
1.1032 - else
1.1033 - {
1.1034 - CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
1.1035 - if (pPlugin)
1.1036 - {
1.1037 - owner = pPlugin->GetFilename();
1.1038 - }
1.1039 - }
1.1040 - }
1.1041 - }
1.1042 - else
1.1043 - {
1.1044 - owner = "NONE";
1.1045 - }
1.1046 - const char *type = "ANON";
1.1047 - QHandleType *pType = &m_Types[m_Handles[i].type];
1.1048 - if (pType->nameIdx != -1)
1.1049 - {
1.1050 - type = m_strtab->GetString(pType->nameIdx);
1.1051 - }
1.1052 - rep("0x%08x\t%-20.20s\t%-20.20s", index, owner, type);
1.1053 - }
1.1054 -}
1.1055 -