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