core/systems/HandleSys.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jan 25 21:50:45 2007 +0000 (2007-01-25)
changeset 364 99f3e60a7f68
parent 351 7c219cde57e7
child 370 d3a484f98f6d
permissions -rw-r--r--
fixed a build error
renamed SMC_CreateParse to SMC_CreateParser
     1 #include "HandleSys.h"
     2 #include "ShareSys.h"
     3 #include "PluginSys.h"
     4 #include <assert.h>
     5 #include <string.h>
     6 
     7 HandleSystem g_HandleSys;
     8 
     9 QHandle *ignore_handle;
    10 
    11 inline HandleType_t TypeParent(HandleType_t type)
    12 {
    13 	return (type & ~HANDLESYS_SUBTYPE_MASK);
    14 }
    15 
    16 inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
    17 {
    18 	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
    19 }
    20 
    21 HandleSystem::HandleSystem()
    22 {
    23 	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
    24 	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
    25 
    26 	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
    27 	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
    28 
    29 	m_TypeLookup = sm_trie_create();
    30 	m_strtab = new BaseStringTable(512);
    31 
    32 	m_TypeTail = 0;
    33 }
    34 
    35 HandleSystem::~HandleSystem()
    36 {
    37 	delete [] m_Handles;
    38 	delete [] m_Types;
    39 	sm_trie_destroy(m_TypeLookup);
    40 	delete m_strtab;
    41 }
    42 
    43 
    44 HandleType_t HandleSystem::CreateType(const char *name, 
    45 									  IHandleTypeDispatch *dispatch, 
    46 									  HandleType_t parent, 
    47 									  const TypeAccess *typeAccess, 
    48 									  const HandleAccess *hndlAccess, 
    49 									  IdentityToken_t *ident,
    50 									  HandleError *err)
    51 {
    52 	if (!dispatch)
    53 	{
    54 		if (err)
    55 		{
    56 			*err = HandleError_Parameter;
    57 		}
    58 		return 0;
    59 	}
    60 
    61 	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    62 	{
    63 		if (err)
    64 		{
    65 			*err = HandleError_Version;
    66 		}
    67 		return 0;
    68 	}
    69 
    70 	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    71 	{
    72 		if (err)
    73 		{
    74 			*err = HandleError_Version;
    75 		}
    76 		return 0;
    77 	}
    78 
    79 	bool isChild = false;
    80 
    81 	if (parent != 0)
    82 	{
    83 		isChild = true;
    84 		if (parent & HANDLESYS_SUBTYPE_MASK)
    85 		{
    86 			if (err)
    87 			{
    88 				*err = HandleError_NoInherit;
    89 			}
    90 			return 0;
    91 		}
    92 		if (parent >= HANDLESYS_TYPEARRAY_SIZE
    93 			|| m_Types[parent].dispatch == NULL)
    94 		{
    95 			if (err)
    96 			{
    97 				*err = HandleError_Parameter;
    98 			}
    99 			return 0;
   100 		}
   101 		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
   102 			&& (m_Types[parent].typeSec.ident != ident))
   103 		{
   104 			if (err)
   105 			{
   106 				*err = HandleError_Access;
   107 			}
   108 			return 0;
   109 		}
   110 	}
   111 
   112 	if (name && name[0] != '\0')
   113 	{
   114 		if (sm_trie_retrieve(m_TypeLookup, name, NULL))
   115 		{
   116 			if (err)
   117 			{
   118 				*err = HandleError_Parameter;
   119 			}
   120 			return 0;
   121 		}
   122 	}
   123 
   124 	unsigned int index;
   125 
   126 	if (isChild)
   127 	{
   128 		QHandleType *pParent = &m_Types[parent];
   129 		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
   130 		{
   131 			if (err)
   132 			{
   133 				*err = HandleError_Limit;
   134 			}
   135 			return 0;
   136 		}
   137 		index = 0;
   138 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   139 		{
   140 			if (m_Types[parent + i].dispatch == NULL)
   141 			{
   142 				index = parent + i;
   143 				break;
   144 			}
   145 		}
   146 		if (!index)
   147 		{
   148 			if (err)
   149 			{
   150 				*err = HandleError_Limit;
   151 			}
   152 			return 0;
   153 		}
   154 		pParent->children++;
   155 	} else {
   156 		if (m_FreeTypes == 0)
   157 		{
   158 			/* Reserve another index */
   159 			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
   160 			{
   161 				if (err)
   162 				{
   163 					*err = HandleError_Limit;
   164 				}
   165 				return 0;
   166 			} else {
   167 				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
   168 				index = m_TypeTail;
   169 			}
   170 		} else {
   171 			/* The "free array" is compacted into the normal array for easiness */
   172 			index = m_Types[m_FreeTypes--].freeID;
   173 		}
   174 	}
   175 
   176 	QHandleType *pType = &m_Types[index];
   177 	
   178 	pType->dispatch = dispatch;
   179 	if (name && name[0] != '\0')
   180 	{
   181 		pType->nameIdx = m_strtab->AddString(name);
   182 		sm_trie_insert(m_TypeLookup, name, (void *)pType);
   183 	} else {
   184 		pType->nameIdx = -1;
   185 	}
   186 
   187 	pType->opened = 0;
   188 
   189 	if (typeAccess)
   190 	{
   191 		pType->typeSec = *typeAccess;
   192 	} else {
   193 		InitAccessDefaults(&pType->typeSec, NULL);
   194 		pType->typeSec.ident = ident;
   195 	}
   196 
   197 	if (hndlAccess)
   198 	{
   199 		pType->hndlSec = *hndlAccess;
   200 	} else {
   201 		InitAccessDefaults(NULL, &pType->hndlSec);
   202 	}
   203 
   204 	if (!isChild)
   205 	{
   206 		pType->children = 0;
   207 	}
   208 
   209 	return index;
   210 }
   211 
   212 bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
   213 {
   214 	QHandleType *_type;
   215 
   216 	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
   217 	{
   218 		return false;
   219 	}
   220 
   221 	unsigned int offset = _type - m_Types;
   222 
   223 	if (type)
   224 	{
   225 		*type = offset;
   226 	}
   227 
   228 	return true;
   229 }
   230 
   231 HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
   232 						   QHandle **in_pHandle, 
   233 						   unsigned int *in_index, 
   234 						   Handle_t *in_handle,
   235 						   IdentityToken_t *owner,
   236 						   bool identity)
   237 {
   238 	unsigned int owner_index = 0;
   239 
   240 	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
   241 	{
   242 		return HandleError_Identity;
   243 	}
   244 
   245 	unsigned int handle;
   246 	if (m_FreeHandles == 0)
   247 	{
   248 		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
   249 		{
   250 			return HandleError_Limit;;
   251 		}
   252 		handle = ++m_HandleTail;
   253 	} else {
   254 		handle = m_Handles[m_FreeHandles--].freeID;
   255 	}
   256 
   257 	QHandle *pHandle = &m_Handles[handle];
   258 	
   259 	assert(pHandle->set == false);
   260 
   261 	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
   262 	{
   263 		m_HSerial = 1;
   264 	}
   265 
   266 	/* Set essential information */
   267 	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
   268 	pHandle->refcount = 1;
   269 	pHandle->type = type;
   270 	pHandle->serial = m_HSerial;
   271 	pHandle->owner = owner;
   272 	pHandle->ch_next = 0;
   273 
   274 	/* Create the hash value */
   275 	Handle_t hash = pHandle->serial;
   276 	hash <<= 16;
   277 	hash |= handle;
   278 
   279 	/* Add a reference count to the type */
   280 	m_Types[type].opened++;
   281 
   282 	/* Output */
   283 	*in_pHandle = pHandle;
   284 	*in_index = handle;
   285 	*in_handle = hash;
   286 
   287 	/* Decode the identity token 
   288 	 * For now, we don't allow nested ownership
   289 	 */
   290 	if (owner && !identity)
   291 	{
   292 		QHandle *pIdentity = &m_Handles[owner_index];
   293 		if (pIdentity->ch_prev == 0)
   294 		{
   295 			pIdentity->ch_prev = handle;
   296 			pIdentity->ch_next = handle;
   297 			pHandle->ch_prev = 0;
   298 		} else {
   299 			/* Link previous node to us (forward) */
   300 			m_Handles[pIdentity->ch_next].ch_next = handle;
   301 			/* Link us to previous node (backwards) */
   302 			pHandle->ch_prev = pIdentity->ch_next;
   303 			/* Set new tail */
   304 			pIdentity->ch_next = handle;
   305 		}
   306 		pIdentity->refcount++;
   307 	} else {
   308 		pHandle->ch_prev = 0;
   309 	}
   310 
   311 	return HandleError_None;
   312 }
   313 
   314 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
   315 {
   316 	if (!type
   317 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   318 		|| m_Types[type].dispatch == NULL)
   319 	{
   320 		return;
   321 	}
   322 
   323 	m_Types[type].typeSec.ident = pToken;
   324 }
   325 
   326 Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity)
   327 {
   328 	if (!type 
   329 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   330 		|| m_Types[type].dispatch == NULL)
   331 	{
   332 		if (err)
   333 		{
   334 			*err = HandleError_Parameter;
   335 		}
   336 		return 0;
   337 	}
   338 
   339 	/* Check to see if we're allowed to create this handle type */
   340 	QHandleType *pType = &m_Types[type];
   341 	if (!pType->typeSec.access[HTypeAccess_Create]
   342 	&& (!pType->typeSec.ident
   343 		|| pType->typeSec.ident != ident))
   344 	{
   345 		if (err)
   346 		{
   347 			*err = HandleError_Access;
   348 		}
   349 		return 0;
   350 	}
   351 
   352 	unsigned int index;
   353 	Handle_t handle;
   354 	QHandle *pHandle;
   355 	HandleError _err;
   356 
   357 	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
   358 	{
   359 		if (err)
   360 		{
   361 			*err = _err;
   362 		}
   363 		return 0;
   364 	}
   365 
   366 	pHandle->object = object;
   367 	pHandle->clone = 0;
   368 
   369 	return handle;
   370 }
   371 
   372 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
   373 {
   374 	return CreateHandleEx(type, object, owner, ident, err, false);
   375 }
   376 
   377 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
   378 {
   379 	/* Check the type inheritance */
   380 	if (intype & HANDLESYS_SUBTYPE_MASK)
   381 	{
   382 		if (intype != outtype
   383 			&& (TypeParent(intype) != TypeParent(outtype)))
   384 		{
   385 			return false;
   386 		}
   387 	} else {
   388 		if (intype != outtype)
   389 		{
   390 			return false;
   391 		}
   392 	}
   393 
   394 	return true;
   395 }
   396 
   397 HandleError HandleSystem::GetHandle(Handle_t handle,
   398 									IdentityToken_t *ident, 
   399 									QHandle **in_pHandle, 
   400 									unsigned int *in_index,
   401 									bool ignoreFree)
   402 {
   403 	unsigned int serial = (handle >> 16);
   404 	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
   405 
   406 	if (index == 0 || index == 0xFFFF)
   407 	{
   408 		return HandleError_Index;
   409 	}
   410 
   411 	QHandle *pHandle = &m_Handles[index];
   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;
   698 #if defined _DEBUG
   699 		unsigned int old_index = 0;
   700 #endif
   701 		while ((ch_index = pHandle->ch_next) != 0)
   702 		{
   703 			pLocal = &m_Handles[ch_index];
   704 #if defined _DEBUG
   705 			assert(old_index != ch_index);
   706 			assert(pLocal->set == HandleSet_Used);
   707 			old_index = ch_index;
   708 #endif
   709 			FreeHandle(pLocal, ch_index);
   710 		}
   711 	}
   712 
   713 	pHandle->set = HandleSet_None;
   714 	m_Types[pHandle->type].opened--;
   715 	m_Handles[++m_FreeHandles].freeID = index;
   716 }
   717 
   718 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
   719 {
   720 	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
   721 	{
   722 		return false;
   723 	}
   724 
   725 	QHandleType *pType = &m_Types[type];
   726 
   727 	if (pType->typeSec.ident
   728 		&& pType->typeSec.ident != ident)
   729 	{
   730 		return false;
   731 	}
   732 
   733 	if (pType->dispatch == NULL)
   734 	{
   735 		return false;
   736 	}
   737 
   738 	/* Remove children if we have to */
   739 	if (!(type & HANDLESYS_SUBTYPE_MASK))
   740 	{
   741 		QHandleType *childType;
   742 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   743 		{
   744 			childType = &m_Types[type + i];
   745 			if (childType->dispatch)
   746 			{
   747 				RemoveType(type + i, childType->typeSec.ident);
   748 			}
   749 		}
   750 		/* Link us into the free chain */
   751 		m_Types[++m_FreeTypes].freeID = type;
   752 	}
   753 
   754 	/* Invalidate the type now */
   755 	IHandleTypeDispatch *dispatch = pType->dispatch;
   756 	pType->dispatch = NULL;
   757 
   758 	/* Make sure nothing is using this type. */
   759 	if (pType->opened)
   760 	{
   761 		QHandle *pHandle;
   762 		for (unsigned int i=1; i<=m_HandleTail; i++)
   763 		{
   764 			pHandle = &m_Handles[i];
   765 			if (!pHandle->set || pHandle->type != type)
   766 			{
   767 				continue;
   768 			}
   769 			if (pHandle->clone)
   770 			{
   771 				/* Get parent */
   772 				QHandle *pOther = &m_Handles[pHandle->clone];
   773 				if (--pOther->refcount == 0)
   774 				{
   775 					/* Free! */
   776 					dispatch->OnHandleDestroy(type, pOther->object);
   777 					ReleasePrimHandle(pHandle->clone);
   778 				}
   779 				/* Unlink ourselves since we don't have a reference count */
   780 				ReleasePrimHandle(i);
   781 			} else {
   782 				/* If it's not a clone, we still have to check the reference count.
   783 				 * Either way, we'll be destroyed eventually because the handle types do not change.
   784 				 */
   785 				if (--pHandle->refcount == 0)
   786 				{
   787 					/* Free! */
   788 					dispatch->OnHandleDestroy(type, pHandle->object);
   789 					ReleasePrimHandle(i);
   790 				}
   791 			}
   792 			if (pType->opened == 0)
   793 			{
   794 				break;
   795 			}
   796 		}
   797 	}
   798 
   799 	return true;
   800 }
   801 
   802 bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
   803 {
   804 	if (pTypeAccess)
   805 	{
   806 		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   807 		{
   808 			return false;
   809 		}
   810 		pTypeAccess->access[HTypeAccess_Create] = false;
   811 		pTypeAccess->access[HTypeAccess_Inherit] = false;
   812 		pTypeAccess->ident = NULL;
   813 	}
   814 
   815 	if (pHandleAccess)
   816 	{
   817 		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   818 		{
   819 			return false;
   820 		}
   821 
   822 		pHandleAccess->access[HandleAccess_Clone] = 0;
   823 		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
   824 		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
   825 	}
   826 
   827 	return true;
   828 }