6 HandleSystem g_HandleSys;
8 QHandle *ignore_handle;
10 inline HandleType_t TypeParent(HandleType_t type)
12 return (type & ~HANDLESYS_SUBTYPE_MASK);
15 inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
17 return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
20 HandleSystem::HandleSystem()
22 m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
23 memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
25 m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
26 memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
28 m_TypeLookup = sm_trie_create();
29 m_strtab = new BaseStringTable(512);
34 HandleSystem::~HandleSystem()
38 sm_trie_destroy(m_TypeLookup);
43 HandleType_t HandleSystem::CreateType(const char *name,
44 IHandleTypeDispatch *dispatch,
46 const TypeAccess *typeAccess,
47 const HandleAccess *hndlAccess,
48 IdentityToken_t *ident,
55 *err = HandleError_Parameter;
60 if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
64 *err = HandleError_Version;
69 if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
73 *err = HandleError_Version;
83 if (parent & HANDLESYS_SUBTYPE_MASK)
87 *err = HandleError_NoInherit;
91 if (parent >= HANDLESYS_TYPEARRAY_SIZE
92 || m_Types[parent].dispatch == NULL)
96 *err = HandleError_Parameter;
100 if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
101 && (m_Types[parent].typeSec.ident != ident))
105 *err = HandleError_Access;
111 if (name && name[0] != '\0')
113 if (sm_trie_retrieve(m_TypeLookup, name, NULL))
117 *err = HandleError_Parameter;
127 QHandleType *pParent = &m_Types[parent];
128 if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
132 *err = HandleError_Limit;
137 for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
139 if (m_Types[parent + i].dispatch == NULL)
149 *err = HandleError_Limit;
155 if (m_FreeTypes == 0)
157 /* Reserve another index */
158 if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
162 *err = HandleError_Limit;
166 m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
170 /* The "free array" is compacted into the normal array for easiness */
171 index = m_Types[m_FreeTypes--].freeID;
175 QHandleType *pType = &m_Types[index];
177 pType->dispatch = dispatch;
178 if (name && name[0] != '\0')
180 pType->nameIdx = m_strtab->AddString(name);
181 sm_trie_insert(m_TypeLookup, name, (void *)pType);
190 pType->typeSec = *typeAccess;
192 InitAccessDefaults(&pType->typeSec, NULL);
193 pType->typeSec.ident = ident;
198 pType->hndlSec = *hndlAccess;
200 InitAccessDefaults(NULL, &pType->hndlSec);
211 bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
215 if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
220 unsigned int offset = _type - m_Types;
230 HandleError HandleSystem::MakePrimHandle(HandleType_t type,
231 QHandle **in_pHandle,
232 unsigned int *in_index,
234 IdentityToken_t *owner,
237 unsigned int owner_index = 0;
239 if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
241 return HandleError_Identity;
245 if (m_FreeHandles == 0)
247 if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
249 return HandleError_Limit;;
251 handle = ++m_HandleTail;
253 handle = m_Handles[m_FreeHandles--].freeID;
256 QHandle *pHandle = &m_Handles[handle];
258 assert(pHandle->set == false);
260 if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
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;
273 /* Create the hash value */
274 Handle_t hash = pHandle->serial;
278 /* Add a reference count to the type */
279 m_Types[type].opened++;
282 *in_pHandle = pHandle;
286 /* Decode the identity token
287 * For now, we don't allow nested ownership
289 if (owner && !identity)
291 QHandle *pIdentity = &m_Handles[owner_index];
292 if (pIdentity->ch_prev == 0)
294 pIdentity->ch_prev = handle;
295 pIdentity->ch_next = handle;
296 pHandle->ch_prev = 0;
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;
303 pIdentity->ch_next = handle;
305 pIdentity->refcount++;
307 pHandle->ch_prev = 0;
310 return HandleError_None;
313 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
316 || type >= HANDLESYS_TYPEARRAY_SIZE
317 || m_Types[type].dispatch == NULL)
322 m_Types[type].typeSec.ident = pToken;
325 Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity)
328 || type >= HANDLESYS_TYPEARRAY_SIZE
329 || m_Types[type].dispatch == NULL)
333 *err = HandleError_Parameter;
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))
346 *err = HandleError_Access;
356 if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
365 pHandle->object = object;
371 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
373 return CreateHandleEx(type, object, owner, ident, err, false);
376 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
378 /* Check the type inheritance */
379 if (intype & HANDLESYS_SUBTYPE_MASK)
381 if (intype != outtype
382 && (TypeParent(intype) != TypeParent(outtype)))
387 if (intype != outtype)
396 HandleError HandleSystem::GetHandle(Handle_t handle,
397 IdentityToken_t *ident,
398 QHandle **in_pHandle,
399 unsigned int *in_index,
402 unsigned int serial = (handle >> 16);
403 unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
405 if (index == 0 || index == 0xFFFF)
407 return HandleError_Index;
410 QHandle *pHandle = &m_Handles[index];
411 QHandleType *pType = &m_Types[pHandle->type];
414 || (pHandle->set == HandleSet_Freed && !ignoreFree))
416 return HandleError_Freed;
417 } else if (pHandle->set == HandleSet_Identity
418 && ident != g_ShareSys.GetIdentRoot())
420 /* Only IdentityHandle() can read this! */
421 return HandleError_Identity;
423 if (pHandle->serial != serial)
425 return HandleError_Changed;
428 *in_pHandle = pHandle;
431 return HandleError_None;
434 bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
436 QHandleType *pType = &m_Types[pHandle->type];
437 unsigned int access = pType->hndlSec.access[right];
439 /* Check if the type's identity matches */
440 if (access & HANDLE_RESTRICT_IDENTITY)
442 IdentityToken_t *owner = pType->typeSec.ident;
444 || (!pSecurity || pSecurity->pIdentity != owner))
450 /* Check if the owner is allowed */
451 if (access & HANDLE_RESTRICT_OWNER)
453 IdentityToken_t *owner = pHandle->owner;
455 && (!pSecurity || pSecurity->pOwner != owner))
464 HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
466 /* Get a new Handle ID */
467 unsigned int new_index;
472 if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
477 pNewHandle->clone = index;
480 *newhandle = new_handle;
482 return HandleError_None;
485 HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
490 IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
492 if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
497 /* Identities cannot be cloned */
498 if (pHandle->set == HandleSet_Identity)
500 return HandleError_Identity;
503 /* Check if the handle can be cloned */
504 if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
506 return HandleError_Access;
509 /* Make sure we're not cloning a clone */
512 QHandle *pParent = &m_Handles[pHandle->clone];
513 return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
516 return CloneHandle(pHandle, index, newhandle, newOwner);
519 HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
521 QHandleType *pType = &m_Types[pHandle->type];
525 /* If we're a clone, decrease the parent reference count */
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];
534 /* Release the clone now */
535 ReleasePrimHandle(index);
537 /* Decrement the master's reference count */
538 if (--pMaster->refcount == 0)
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);
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
549 ReleasePrimHandle(index);
551 /* Decrement, free if necessary */
552 if (--pHandle->refcount == 0)
554 pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
555 ReleasePrimHandle(index);
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 */
562 UnlinkHandleFromOwner(pHandle, index);
567 return HandleError_None;
570 HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
575 IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
577 if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
582 if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
584 return HandleError_Access;
587 return FreeHandle(pHandle, index);
590 HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
595 IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
597 if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
602 if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
604 return HandleError_Access;
607 /* Check the type inheritance */
608 if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
610 if (pHandle->type != type
611 && (TypeParent(pHandle->type) != TypeParent(type)))
613 return HandleError_Type;
616 if (pHandle->type != type)
618 return HandleError_Type;
624 /* if we're a clone, the rules change - object is ONLY in our reference */
627 pHandle = &m_Handles[pHandle->clone];
629 *object = pHandle->object;
632 return HandleError_None;
635 void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
637 /* Unlink us if necessary */
638 unsigned int ident_index;
639 if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
642 assert(pHandle->owner == 0);
645 /* Note that since 0 is an invalid handle, if any of these links are 0,
646 * the data can still be set.
648 QHandle *pIdentity = &m_Handles[ident_index];
650 /* Unlink case: We're the head AND tail node */
651 if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
653 pIdentity->ch_prev = 0;
654 pIdentity->ch_next = 0;
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;
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;
670 /* Unlink case: We're in the middle! */
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;
678 /* Lastly, decrease the reference count */
679 pIdentity->refcount--;
682 void HandleSystem::ReleasePrimHandle(unsigned int index)
684 QHandle *pHandle = &m_Handles[index];
685 HandleSet set = pHandle->set;
687 if (pHandle->owner && (set != HandleSet_Identity))
689 UnlinkHandleFromOwner(pHandle, index);
692 /* Were we an identity ourself? */
694 if (set == HandleSet_Identity)
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)
700 pLocal = &m_Handles[ch_index];
702 assert(old_index != ch_index);
703 assert(pLocal->set == HandleSet_Used);
704 old_index = ch_index;
706 FreeHandle(pLocal, ch_index);
710 pHandle->set = HandleSet_None;
711 m_Types[pHandle->type].opened--;
712 m_Handles[++m_FreeHandles].freeID = index;
715 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
717 if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
722 QHandleType *pType = &m_Types[type];
724 if (pType->typeSec.ident
725 && pType->typeSec.ident != ident)
730 if (pType->dispatch == NULL)
735 /* Remove children if we have to */
736 if (!(type & HANDLESYS_SUBTYPE_MASK))
738 QHandleType *childType;
739 for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
741 childType = &m_Types[type + i];
742 if (childType->dispatch)
744 RemoveType(type + i, childType->typeSec.ident);
747 /* Link us into the free chain */
748 m_Types[++m_FreeTypes].freeID = type;
751 /* Invalidate the type now */
752 IHandleTypeDispatch *dispatch = pType->dispatch;
753 pType->dispatch = NULL;
755 /* Make sure nothing is using this type. */
759 for (unsigned int i=1; i<=m_HandleTail; i++)
761 pHandle = &m_Handles[i];
762 if (!pHandle->set || pHandle->type != type)
769 QHandle *pOther = &m_Handles[pHandle->clone];
770 if (--pOther->refcount == 0)
773 dispatch->OnHandleDestroy(type, pOther->object);
774 ReleasePrimHandle(pHandle->clone);
776 /* Unlink ourselves since we don't have a reference count */
777 ReleasePrimHandle(i);
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.
782 if (--pHandle->refcount == 0)
785 dispatch->OnHandleDestroy(type, pHandle->object);
786 ReleasePrimHandle(i);
789 if (pType->opened == 0)
799 bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
803 if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
807 pTypeAccess->access[HTypeAccess_Create] = false;
808 pTypeAccess->access[HTypeAccess_Inherit] = false;
809 pTypeAccess->ident = NULL;
814 if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
819 pHandleAccess->access[HandleAccess_Clone] = 0;
820 pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
821 pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;