core/systems/HandleSys.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sun Jul 15 01:04:34 2007 +0000 (2007-07-15)
changeset 1112 152ceef17866
parent 900 b38c83f9d526
child 1231 17badaf66ce4
permissions -rw-r--r--
added amb292, optional natives
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "HandleSys.h"
    16 #include "ShareSys.h"
    17 #include "PluginSys.h"
    18 #include "ExtensionSys.h"
    19 #include <assert.h>
    20 #include <string.h>
    21 
    22 HandleSystem g_HandleSys;
    23 
    24 QHandle *ignore_handle;
    25 
    26 inline HandleType_t TypeParent(HandleType_t type)
    27 {
    28 	return (type & ~HANDLESYS_SUBTYPE_MASK);
    29 }
    30 
    31 inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
    32 {
    33 	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
    34 }
    35 
    36 HandleSystem::HandleSystem()
    37 {
    38 	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
    39 	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
    40 
    41 	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
    42 	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
    43 
    44 	m_TypeLookup = sm_trie_create();
    45 	m_strtab = new BaseStringTable(512);
    46 
    47 	m_TypeTail = 0;
    48 }
    49 
    50 HandleSystem::~HandleSystem()
    51 {
    52 	delete [] m_Handles;
    53 	delete [] m_Types;
    54 	sm_trie_destroy(m_TypeLookup);
    55 	delete m_strtab;
    56 }
    57 
    58 
    59 HandleType_t HandleSystem::CreateType(const char *name, 
    60 									  IHandleTypeDispatch *dispatch, 
    61 									  HandleType_t parent, 
    62 									  const TypeAccess *typeAccess, 
    63 									  const HandleAccess *hndlAccess, 
    64 									  IdentityToken_t *ident,
    65 									  HandleError *err)
    66 {
    67 	if (!dispatch)
    68 	{
    69 		if (err)
    70 		{
    71 			*err = HandleError_Parameter;
    72 		}
    73 		return 0;
    74 	}
    75 
    76 	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    77 	{
    78 		if (err)
    79 		{
    80 			*err = HandleError_Version;
    81 		}
    82 		return 0;
    83 	}
    84 
    85 	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    86 	{
    87 		if (err)
    88 		{
    89 			*err = HandleError_Version;
    90 		}
    91 		return 0;
    92 	}
    93 
    94 	bool isChild = false;
    95 
    96 	if (parent != 0)
    97 	{
    98 		isChild = true;
    99 		if (parent & HANDLESYS_SUBTYPE_MASK)
   100 		{
   101 			if (err)
   102 			{
   103 				*err = HandleError_NoInherit;
   104 			}
   105 			return 0;
   106 		}
   107 		if (parent >= HANDLESYS_TYPEARRAY_SIZE
   108 			|| m_Types[parent].dispatch == NULL)
   109 		{
   110 			if (err)
   111 			{
   112 				*err = HandleError_Parameter;
   113 			}
   114 			return 0;
   115 		}
   116 		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
   117 			&& (m_Types[parent].typeSec.ident != ident))
   118 		{
   119 			if (err)
   120 			{
   121 				*err = HandleError_Access;
   122 			}
   123 			return 0;
   124 		}
   125 	}
   126 
   127 	if (name && name[0] != '\0')
   128 	{
   129 		if (sm_trie_retrieve(m_TypeLookup, name, NULL))
   130 		{
   131 			if (err)
   132 			{
   133 				*err = HandleError_Parameter;
   134 			}
   135 			return 0;
   136 		}
   137 	}
   138 
   139 	unsigned int index;
   140 
   141 	if (isChild)
   142 	{
   143 		QHandleType *pParent = &m_Types[parent];
   144 		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
   145 		{
   146 			if (err)
   147 			{
   148 				*err = HandleError_Limit;
   149 			}
   150 			return 0;
   151 		}
   152 		index = 0;
   153 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   154 		{
   155 			if (m_Types[parent + i].dispatch == NULL)
   156 			{
   157 				index = parent + i;
   158 				break;
   159 			}
   160 		}
   161 		if (!index)
   162 		{
   163 			if (err)
   164 			{
   165 				*err = HandleError_Limit;
   166 			}
   167 			return 0;
   168 		}
   169 		pParent->children++;
   170 	} else {
   171 		if (m_FreeTypes == 0)
   172 		{
   173 			/* Reserve another index */
   174 			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
   175 			{
   176 				if (err)
   177 				{
   178 					*err = HandleError_Limit;
   179 				}
   180 				return 0;
   181 			} else {
   182 				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
   183 				index = m_TypeTail;
   184 			}
   185 		} else {
   186 			/* The "free array" is compacted into the normal array for easiness */
   187 			index = m_Types[m_FreeTypes--].freeID;
   188 		}
   189 	}
   190 
   191 	QHandleType *pType = &m_Types[index];
   192 	
   193 	pType->dispatch = dispatch;
   194 	if (name && name[0] != '\0')
   195 	{
   196 		pType->nameIdx = m_strtab->AddString(name);
   197 		sm_trie_insert(m_TypeLookup, name, (void *)pType);
   198 	} else {
   199 		pType->nameIdx = -1;
   200 	}
   201 
   202 	pType->opened = 0;
   203 
   204 	if (typeAccess)
   205 	{
   206 		pType->typeSec = *typeAccess;
   207 	} else {
   208 		InitAccessDefaults(&pType->typeSec, NULL);
   209 		pType->typeSec.ident = ident;
   210 	}
   211 
   212 	if (hndlAccess)
   213 	{
   214 		pType->hndlSec = *hndlAccess;
   215 	} else {
   216 		InitAccessDefaults(NULL, &pType->hndlSec);
   217 	}
   218 
   219 	if (!isChild)
   220 	{
   221 		pType->children = 0;
   222 	}
   223 
   224 	return index;
   225 }
   226 
   227 bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
   228 {
   229 	QHandleType *_type;
   230 
   231 	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
   232 	{
   233 		return false;
   234 	}
   235 
   236 	unsigned int offset = _type - m_Types;
   237 
   238 	if (type)
   239 	{
   240 		*type = offset;
   241 	}
   242 
   243 	return true;
   244 }
   245 
   246 HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
   247 						   QHandle **in_pHandle, 
   248 						   unsigned int *in_index, 
   249 						   Handle_t *in_handle,
   250 						   IdentityToken_t *owner,
   251 						   bool identity)
   252 {
   253 	unsigned int owner_index = 0;
   254 
   255 	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
   256 	{
   257 		return HandleError_Identity;
   258 	}
   259 
   260 	unsigned int handle;
   261 	if (m_FreeHandles == 0)
   262 	{
   263 		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
   264 		{
   265 			return HandleError_Limit;;
   266 		}
   267 		handle = ++m_HandleTail;
   268 	} else {
   269 		handle = m_Handles[m_FreeHandles--].freeID;
   270 	}
   271 
   272 	QHandle *pHandle = &m_Handles[handle];
   273 	
   274 	assert(pHandle->set == false);
   275 
   276 	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
   277 	{
   278 		m_HSerial = 1;
   279 	}
   280 
   281 	/* Set essential information */
   282 	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
   283 	pHandle->refcount = 1;
   284 	pHandle->type = type;
   285 	pHandle->serial = m_HSerial;
   286 	pHandle->owner = owner;
   287 	pHandle->ch_next = 0;
   288 	pHandle->access_special = false;
   289 	pHandle->is_destroying = false;
   290 
   291 	/* Create the hash value */
   292 	Handle_t hash = pHandle->serial;
   293 	hash <<= 16;
   294 	hash |= handle;
   295 
   296 	/* Add a reference count to the type */
   297 	m_Types[type].opened++;
   298 
   299 	/* Output */
   300 	*in_pHandle = pHandle;
   301 	*in_index = handle;
   302 	*in_handle = hash;
   303 
   304 	/* Decode the identity token 
   305 	 * For now, we don't allow nested ownership
   306 	 */
   307 	if (owner && !identity)
   308 	{
   309 		QHandle *pIdentity = &m_Handles[owner_index];
   310 		if (pIdentity->ch_prev == 0)
   311 		{
   312 			pIdentity->ch_prev = handle;
   313 			pIdentity->ch_next = handle;
   314 			pHandle->ch_prev = 0;
   315 		} else {
   316 			/* Link previous node to us (forward) */
   317 			m_Handles[pIdentity->ch_next].ch_next = handle;
   318 			/* Link us to previous node (backwards) */
   319 			pHandle->ch_prev = pIdentity->ch_next;
   320 			/* Set new tail */
   321 			pIdentity->ch_next = handle;
   322 		}
   323 		pIdentity->refcount++;
   324 	} else {
   325 		pHandle->ch_prev = 0;
   326 	}
   327 
   328 	return HandleError_None;
   329 }
   330 
   331 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
   332 {
   333 	if (!type
   334 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   335 		|| m_Types[type].dispatch == NULL)
   336 	{
   337 		return;
   338 	}
   339 
   340 	m_Types[type].typeSec.ident = pToken;
   341 }
   342 
   343 Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
   344 									   void *object, 
   345 									   const HandleSecurity *pSec,
   346 									   HandleError *err, 
   347 									   const HandleAccess *pAccess,
   348 									   bool identity)
   349 {
   350 	IdentityToken_t *ident;
   351 	IdentityToken_t *owner;
   352 
   353 	if (pSec)
   354 	{
   355 		ident = pSec->pIdentity;
   356 		owner = pSec->pOwner;
   357 	} else {
   358 		ident = NULL;
   359 		owner = NULL;
   360 	}
   361 
   362 	if (!type 
   363 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   364 		|| m_Types[type].dispatch == NULL)
   365 	{
   366 		if (err)
   367 		{
   368 			*err = HandleError_Parameter;
   369 		}
   370 		return 0;
   371 	}
   372 
   373 	/* Check to see if we're allowed to create this handle type */
   374 	QHandleType *pType = &m_Types[type];
   375 	if (!pType->typeSec.access[HTypeAccess_Create]
   376 	&& (!pType->typeSec.ident
   377 		|| pType->typeSec.ident != ident))
   378 	{
   379 		if (err)
   380 		{
   381 			*err = HandleError_Access;
   382 		}
   383 		return 0;
   384 	}
   385 
   386 	unsigned int index;
   387 	Handle_t handle;
   388 	QHandle *pHandle;
   389 	HandleError _err;
   390 
   391 	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
   392 	{
   393 		if (err)
   394 		{
   395 			*err = _err;
   396 		}
   397 		return 0;
   398 	}
   399 
   400 	if (pAccess)
   401 	{
   402 		pHandle->access_special = true;
   403 		pHandle->sec = *pAccess;
   404 	}
   405 
   406 	pHandle->object = object;
   407 	pHandle->clone = 0;
   408 
   409 	return handle;
   410 }
   411 
   412 Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
   413 {
   414 	return CreateHandleInt(type, object, pSec, err, pAccess, false);
   415 }
   416 
   417 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
   418 {
   419 	HandleSecurity sec;
   420 
   421 	sec.pIdentity = ident;
   422 	sec.pOwner = owner;
   423 
   424 	return CreateHandleEx(type, object, &sec, NULL, err);
   425 }
   426 
   427 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
   428 {
   429 	/* Check the type inheritance */
   430 	if (intype & HANDLESYS_SUBTYPE_MASK)
   431 	{
   432 		if (intype != outtype
   433 			&& (TypeParent(intype) != TypeParent(outtype)))
   434 		{
   435 			return false;
   436 		}
   437 	} else {
   438 		if (intype != outtype)
   439 		{
   440 			return false;
   441 		}
   442 	}
   443 
   444 	return true;
   445 }
   446 
   447 HandleError HandleSystem::GetHandle(Handle_t handle,
   448 									IdentityToken_t *ident, 
   449 									QHandle **in_pHandle, 
   450 									unsigned int *in_index,
   451 									bool ignoreFree)
   452 {
   453 	unsigned int serial = (handle >> 16);
   454 	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
   455 
   456 	if (index == 0 || index == 0xFFFF)
   457 	{
   458 		return HandleError_Index;
   459 	}
   460 
   461 	QHandle *pHandle = &m_Handles[index];
   462 
   463 	if (!pHandle->set
   464 		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
   465 	{
   466 		return HandleError_Freed;
   467 	} else if (pHandle->set == HandleSet_Identity
   468 			   && ident != g_ShareSys.GetIdentRoot())
   469 	{
   470 		/* Only IdentityHandle() can read this! */
   471 		return HandleError_Identity;
   472 	}
   473 	if (pHandle->serial != serial)
   474 	{
   475 		return HandleError_Changed;
   476 	}
   477 
   478 	*in_pHandle = pHandle;
   479 	*in_index = index;
   480 
   481 	return HandleError_None;
   482 }
   483 
   484 bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
   485 {
   486 	QHandleType *pType = &m_Types[pHandle->type];
   487 	unsigned int access;
   488 
   489 	if (pHandle->access_special)
   490 	{
   491 		access = pHandle->sec.access[right];
   492 	} else {
   493 		access = pType->hndlSec.access[right];
   494 	}
   495 
   496 	/* Check if the type's identity matches */
   497 	if (access & HANDLE_RESTRICT_IDENTITY)
   498 	{
   499 		IdentityToken_t *owner = pType->typeSec.ident;
   500 		if (!owner
   501 			|| (!pSecurity || pSecurity->pIdentity != owner))
   502 		{
   503 			return false;
   504 		}
   505 	}
   506 
   507 	/* Check if the owner is allowed */
   508 	if (access & HANDLE_RESTRICT_OWNER)
   509 	{
   510 		IdentityToken_t *owner = pHandle->owner;
   511 		if (owner
   512 			&& (!pSecurity || pSecurity->pOwner != owner))
   513 		{
   514 			return false;
   515 		}
   516 	}
   517 
   518 	return true;
   519 }
   520 
   521 HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
   522 {
   523 	/* Get a new Handle ID */
   524 	unsigned int new_index;
   525 	QHandle *pNewHandle;
   526 	Handle_t new_handle;
   527 	HandleError err;
   528 
   529 	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
   530 	{
   531 		return err;
   532 	}
   533 
   534 	/* Assign permissions from parent */
   535 	if (pHandle->access_special)
   536 	{
   537 		pNewHandle->access_special = true;
   538 		pNewHandle->sec = pHandle->sec;
   539 	}
   540 
   541 	pNewHandle->clone = index;
   542 	pHandle->refcount++;
   543 
   544 	*newhandle = new_handle;
   545 
   546 	return HandleError_None;
   547 }
   548 
   549 HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
   550 {
   551 	HandleError err;
   552 	QHandle *pHandle;
   553 	unsigned int index;
   554 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   555 
   556 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   557 	{
   558 		return err;
   559 	}
   560 
   561 	/* Identities cannot be cloned */
   562 	if (pHandle->set == HandleSet_Identity)
   563 	{
   564 		return HandleError_Identity;
   565 	}
   566 
   567 	/* Check if the handle can be cloned */
   568 	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
   569 	{
   570 		return HandleError_Access;
   571 	}
   572 
   573 	/* Make sure we're not cloning a clone */
   574 	if (pHandle->clone)
   575 	{
   576 		QHandle *pParent = &m_Handles[pHandle->clone];
   577 		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
   578 	}
   579 
   580 	return CloneHandle(pHandle, index, newhandle, newOwner);
   581 }
   582 
   583 HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
   584 {
   585 	QHandleType *pType = &m_Types[pHandle->type];
   586 
   587 	if (pHandle->clone)
   588 	{
   589 		/* If we're a clone, decrease the parent reference count */
   590 		QHandle *pMaster;
   591 		unsigned int master;
   592 
   593 		/* Note that if we ever have per-handle security, we would need to re-check
   594 		* the access on this Handle. */
   595 		master = pHandle->clone;
   596 		pMaster = &m_Handles[master];
   597 
   598 		/* Release the clone now */
   599 		ReleasePrimHandle(index);
   600 
   601 		/* Decrement the master's reference count */
   602 		if (--pMaster->refcount == 0)
   603 		{
   604 			/* Type should be the same but do this anyway... */
   605 			pType = &m_Types[pMaster->type];
   606 			pMaster->is_destroying = true;
   607 			pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
   608 			ReleasePrimHandle(master);
   609 		}
   610 	} else if (pHandle->set == HandleSet_Identity) {
   611 		/* If we're an identity, skip all this stuff!
   612 		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
   613 		 */
   614 		ReleasePrimHandle(index);
   615 	} else {
   616 		/* Decrement, free if necessary */
   617 		if (--pHandle->refcount == 0)
   618 		{
   619 			pHandle->is_destroying = true;
   620 			pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
   621 			ReleasePrimHandle(index);
   622 		} else {
   623 			/* We must be cloned, so mark ourselves as freed */
   624 			pHandle->set = HandleSet_Freed;
   625 			/* Now, unlink us, so we're not being tracked by the owner */
   626 			if (pHandle->owner)
   627 			{
   628 				UnlinkHandleFromOwner(pHandle, index);
   629 			}
   630 		}
   631 	}
   632 
   633 	return HandleError_None;
   634 }
   635 
   636 HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
   637 {
   638 	unsigned int index;
   639 	QHandle *pHandle;
   640 	HandleError err;
   641 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   642 
   643 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   644 	{
   645 		return err;
   646 	}
   647 
   648 	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
   649 	{
   650 		return HandleError_Access;
   651 	}
   652 
   653 	if (pHandle->is_destroying)
   654 	{
   655 		/* Someone tried to free this recursively.  
   656 		 * We'll just ignore this safely.
   657 		 */
   658 		return HandleError_None;
   659 	}
   660 
   661 	return FreeHandle(pHandle, index);
   662 }
   663 
   664 HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
   665 {
   666 	unsigned int index;
   667 	QHandle *pHandle;
   668 	HandleError err;
   669 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   670 
   671 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   672 	{
   673 		return err;
   674 	}
   675 
   676 	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
   677 	{
   678 		return HandleError_Access;
   679 	}
   680 
   681 	/* Check the type inheritance */
   682 	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
   683 	{
   684 		if (pHandle->type != type
   685 			&& (TypeParent(pHandle->type) != TypeParent(type)))
   686 		{
   687 			return HandleError_Type;
   688 		}
   689 	} else if (type) {
   690 		if (pHandle->type != type)
   691 		{
   692 			return HandleError_Type;
   693 		}
   694 	}
   695 
   696 	if (object)
   697 	{
   698 		/* if we're a clone, the rules change - object is ONLY in our reference */
   699 		if (pHandle->clone)
   700 		{
   701 			pHandle = &m_Handles[pHandle->clone];
   702 		}
   703 		*object = pHandle->object;
   704 	}
   705 
   706 	return HandleError_None;
   707 }
   708 
   709 void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
   710 {
   711 	/* Unlink us if necessary */
   712 	unsigned int ident_index;
   713 	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
   714 	{
   715 		/* Uh-oh! */
   716 		assert(pHandle->owner == 0);
   717 		return;
   718 	}
   719 	/* Note that since 0 is an invalid handle, if any of these links are 0,
   720 	* the data can still be set.
   721 	*/
   722 	QHandle *pIdentity = &m_Handles[ident_index];
   723 
   724 	/* Unlink case: We're the head AND tail node */
   725 	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
   726 	{
   727 		pIdentity->ch_prev = 0;
   728 		pIdentity->ch_next = 0;
   729 	}
   730 	/* Unlink case: We're the head node */
   731 	else if (index == pIdentity->ch_prev) {
   732 		/* Link us to the next in the chain */
   733 		pIdentity->ch_prev = pHandle->ch_next;
   734 		/* Patch up the previous link */
   735 		m_Handles[pHandle->ch_next].ch_prev = 0;
   736 	}
   737 	/* Unlink case: We're the tail node */
   738 	else if (index == pIdentity->ch_next) {
   739 		/* Link us to the previous in the chain */
   740 		pIdentity->ch_next = pHandle->ch_prev;
   741 		/* Patch up the next link */
   742 		m_Handles[pHandle->ch_prev].ch_next = 0;
   743 	}
   744 	/* Unlink case: We're in the middle! */
   745 	else {
   746 		/* Patch the forward reference */
   747 		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
   748 		/* Patch the backward reference */
   749 		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
   750 	}
   751 
   752 	/* Lastly, decrease the reference count */
   753 	pIdentity->refcount--;
   754 }
   755 
   756 void HandleSystem::ReleasePrimHandle(unsigned int index)
   757 {
   758 	QHandle *pHandle = &m_Handles[index];
   759 	HandleSet set = pHandle->set;
   760 
   761 	if (pHandle->owner && (set != HandleSet_Identity))
   762 	{
   763 		UnlinkHandleFromOwner(pHandle, index);
   764 	}
   765 
   766 	/* Were we an identity ourself? */
   767 	QHandle *pLocal;
   768 	if (set == HandleSet_Identity)
   769 	{
   770 		/* Extra work to do.  We need to find everything connected to this identity and release it. */
   771 		unsigned int ch_index;
   772 #if defined _DEBUG
   773 		unsigned int old_index = 0;
   774 #endif
   775 		while ((ch_index = pHandle->ch_next) != 0)
   776 		{
   777 			pLocal = &m_Handles[ch_index];
   778 #if defined _DEBUG
   779 			assert(old_index != ch_index);
   780 			assert(pLocal->set == HandleSet_Used);
   781 			old_index = ch_index;
   782 #endif
   783 			FreeHandle(pLocal, ch_index);
   784 		}
   785 	}
   786 
   787 	pHandle->set = HandleSet_None;
   788 	m_Types[pHandle->type].opened--;
   789 	m_Handles[++m_FreeHandles].freeID = index;
   790 }
   791 
   792 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
   793 {
   794 	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
   795 	{
   796 		return false;
   797 	}
   798 
   799 	QHandleType *pType = &m_Types[type];
   800 
   801 	if (pType->typeSec.ident
   802 		&& pType->typeSec.ident != ident)
   803 	{
   804 		return false;
   805 	}
   806 
   807 	if (pType->dispatch == NULL)
   808 	{
   809 		return false;
   810 	}
   811 
   812 	/* Remove children if we have to */
   813 	if (!(type & HANDLESYS_SUBTYPE_MASK))
   814 	{
   815 		QHandleType *childType;
   816 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   817 		{
   818 			childType = &m_Types[type + i];
   819 			if (childType->dispatch)
   820 			{
   821 				RemoveType(type + i, childType->typeSec.ident);
   822 			}
   823 		}
   824 		/* Link us into the free chain */
   825 		m_Types[++m_FreeTypes].freeID = type;
   826 	}
   827 
   828 	/* Invalidate the type now */
   829 	IHandleTypeDispatch *dispatch = pType->dispatch;
   830 	pType->dispatch = NULL;
   831 
   832 	/* Make sure nothing is using this type. */
   833 	if (pType->opened)
   834 	{
   835 		QHandle *pHandle;
   836 		for (unsigned int i=1; i<=m_HandleTail; i++)
   837 		{
   838 			pHandle = &m_Handles[i];
   839 			if (!pHandle->set || pHandle->type != type)
   840 			{
   841 				continue;
   842 			}
   843 			if (pHandle->clone)
   844 			{
   845 				/* Get parent */
   846 				QHandle *pOther = &m_Handles[pHandle->clone];
   847 				if (--pOther->refcount == 0)
   848 				{
   849 					/* Free! */
   850 					dispatch->OnHandleDestroy(type, pOther->object);
   851 					ReleasePrimHandle(pHandle->clone);
   852 				}
   853 				/* Unlink ourselves since we don't have a reference count */
   854 				ReleasePrimHandle(i);
   855 			} else {
   856 				/* If it's not a clone, we still have to check the reference count.
   857 				 * Either way, we'll be destroyed eventually because the handle types do not change.
   858 				 */
   859 				if (--pHandle->refcount == 0)
   860 				{
   861 					/* Free! */
   862 					dispatch->OnHandleDestroy(type, pHandle->object);
   863 					ReleasePrimHandle(i);
   864 				}
   865 			}
   866 			if (pType->opened == 0)
   867 			{
   868 				break;
   869 			}
   870 		}
   871 	}
   872 
   873 	return true;
   874 }
   875 
   876 bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
   877 {
   878 	if (pTypeAccess)
   879 	{
   880 		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   881 		{
   882 			return false;
   883 		}
   884 		pTypeAccess->access[HTypeAccess_Create] = false;
   885 		pTypeAccess->access[HTypeAccess_Inherit] = false;
   886 		pTypeAccess->ident = NULL;
   887 	}
   888 
   889 	if (pHandleAccess)
   890 	{
   891 		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   892 		{
   893 			return false;
   894 		}
   895 
   896 		pHandleAccess->access[HandleAccess_Clone] = 0;
   897 		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
   898 		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
   899 	}
   900 
   901 	return true;
   902 }
   903 
   904 void HandleSystem::Dump(FILE *fp)
   905 {
   906 	fprintf(fp, "%-10.10s\t%-20.20s\t%-20.20s\n", "Handle", "Owner", "Type");
   907 	fprintf(fp, "---------------------------------------------\n");
   908 	for (unsigned int i=1; i<=m_HandleTail; i++)
   909 	{
   910 		if (m_Handles[i].set == HandleSet_Freed
   911 			|| m_Handles[i].set == HandleSet_Identity)
   912 		{
   913 			continue;
   914 		}
   915 		/* Get the index */
   916 		unsigned int index = (m_Handles[i].serial << 16) | i;
   917 		/* Determine the owner */
   918 		const char *owner = "UNKNOWN";
   919 		if (m_Handles[i].owner)
   920 		{
   921 			IdentityToken_t *pOwner = m_Handles[i].owner;
   922 			if (pOwner == g_pCoreIdent)
   923 			{
   924 				owner = "CORE";
   925 			} else if (pOwner == g_PluginSys.GetIdentity()) {
   926 				owner = "PLUGINSYS";
   927 			} else {
   928 				CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
   929 				if (ext)
   930 				{
   931 					owner = ext->GetFilename();
   932 				} else {
   933 					CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
   934 					if (pPlugin)
   935 					{
   936 						owner = pPlugin->GetFilename();
   937 					}
   938 				}
   939 			}
   940 		} else {
   941 			owner = "NONE";
   942 		}
   943 		const char *type = "ANON";
   944 		QHandleType *pType = &m_Types[m_Handles[i].type];
   945 		if (pType->nameIdx != -1)
   946 		{
   947 			type = m_strtab->GetString(pType->nameIdx);
   948 		}
   949 		fprintf(fp, "0x%08x\t%-20.20s\t%-20.20s\n", index, owner, type);
   950 	}
   951 }