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