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