7 HandleSystem g_HandleSys;
9 QHandle *ignore_handle;
11 inline HandleType_t TypeParent(HandleType_t type)
13 return (type & ~HANDLESYS_SUBTYPE_MASK);
16 inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
18 return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
21 HandleSystem::HandleSystem()
23 m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
24 memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
26 m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
27 memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
29 m_TypeLookup = sm_trie_create();
30 m_strtab = new BaseStringTable(512);
35 HandleSystem::~HandleSystem()
39 sm_trie_destroy(m_TypeLookup);
44 HandleType_t HandleSystem::CreateType(const char *name,
45 IHandleTypeDispatch *dispatch,
47 const TypeAccess *typeAccess,
48 const HandleAccess *hndlAccess,
49 IdentityToken_t *ident,
56 *err = HandleError_Parameter;
61 if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
65 *err = HandleError_Version;
70 if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
74 *err = HandleError_Version;
84 if (parent & HANDLESYS_SUBTYPE_MASK)
88 *err = HandleError_NoInherit;
92 if (parent >= HANDLESYS_TYPEARRAY_SIZE
93 || m_Types[parent].dispatch == NULL)
97 *err = HandleError_Parameter;
101 if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
102 && (m_Types[parent].typeSec.ident != ident))
106 *err = HandleError_Access;
112 if (name && name[0] != '\0')
114 if (sm_trie_retrieve(m_TypeLookup, name, NULL))
118 *err = HandleError_Parameter;
128 QHandleType *pParent = &m_Types[parent];
129 if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
133 *err = HandleError_Limit;
138 for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
140 if (m_Types[parent + i].dispatch == NULL)
150 *err = HandleError_Limit;
156 if (m_FreeTypes == 0)
158 /* Reserve another index */
159 if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
163 *err = HandleError_Limit;
167 m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
171 /* The "free array" is compacted into the normal array for easiness */
172 index = m_Types[m_FreeTypes--].freeID;
176 QHandleType *pType = &m_Types[index];
178 pType->dispatch = dispatch;
179 if (name && name[0] != '\0')
181 pType->nameIdx = m_strtab->AddString(name);
182 sm_trie_insert(m_TypeLookup, name, (void *)pType);
191 pType->typeSec = *typeAccess;
193 InitAccessDefaults(&pType->typeSec, NULL);
194 pType->typeSec.ident = ident;
199 pType->hndlSec = *hndlAccess;
201 InitAccessDefaults(NULL, &pType->hndlSec);
212 bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
216 if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
221 unsigned int offset = _type - m_Types;
231 HandleError HandleSystem::MakePrimHandle(HandleType_t type,
232 QHandle **in_pHandle,
233 unsigned int *in_index,
235 IdentityToken_t *owner,
238 unsigned int owner_index = 0;
240 if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
242 return HandleError_Identity;
246 if (m_FreeHandles == 0)
248 if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
250 return HandleError_Limit;;
252 handle = ++m_HandleTail;
254 handle = m_Handles[m_FreeHandles--].freeID;
257 QHandle *pHandle = &m_Handles[handle];
259 assert(pHandle->set == false);
261 if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
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;
274 /* Create the hash value */
275 Handle_t hash = pHandle->serial;
279 /* Add a reference count to the type */
280 m_Types[type].opened++;
283 *in_pHandle = pHandle;
287 /* Decode the identity token
288 * For now, we don't allow nested ownership
290 if (owner && !identity)
292 QHandle *pIdentity = &m_Handles[owner_index];
293 if (pIdentity->ch_prev == 0)
295 pIdentity->ch_prev = handle;
296 pIdentity->ch_next = handle;
297 pHandle->ch_prev = 0;
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;
304 pIdentity->ch_next = handle;
306 pIdentity->refcount++;
308 pHandle->ch_prev = 0;
311 return HandleError_None;
314 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
317 || type >= HANDLESYS_TYPEARRAY_SIZE
318 || m_Types[type].dispatch == NULL)
323 m_Types[type].typeSec.ident = pToken;
326 Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err, bool identity)
329 || type >= HANDLESYS_TYPEARRAY_SIZE
330 || m_Types[type].dispatch == NULL)
334 *err = HandleError_Parameter;
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))
347 *err = HandleError_Access;
357 if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
366 pHandle->object = object;
372 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
374 return CreateHandleEx(type, object, owner, ident, err, false);
377 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
379 /* Check the type inheritance */
380 if (intype & HANDLESYS_SUBTYPE_MASK)
382 if (intype != outtype
383 && (TypeParent(intype) != TypeParent(outtype)))
388 if (intype != outtype)
397 HandleError HandleSystem::GetHandle(Handle_t handle,
398 IdentityToken_t *ident,
399 QHandle **in_pHandle,
400 unsigned int *in_index,
403 unsigned int serial = (handle >> 16);
404 unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
406 if (index == 0 || index == 0xFFFF)
408 return HandleError_Index;
411 QHandle *pHandle = &m_Handles[index];
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;
699 unsigned int old_index = 0;
701 while ((ch_index = pHandle->ch_next) != 0)
703 pLocal = &m_Handles[ch_index];
705 assert(old_index != ch_index);
706 assert(pLocal->set == HandleSet_Used);
707 old_index = ch_index;
709 FreeHandle(pLocal, ch_index);
713 pHandle->set = HandleSet_None;
714 m_Types[pHandle->type].opened--;
715 m_Handles[++m_FreeHandles].freeID = index;
718 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
720 if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
725 QHandleType *pType = &m_Types[type];
727 if (pType->typeSec.ident
728 && pType->typeSec.ident != ident)
733 if (pType->dispatch == NULL)
738 /* Remove children if we have to */
739 if (!(type & HANDLESYS_SUBTYPE_MASK))
741 QHandleType *childType;
742 for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
744 childType = &m_Types[type + i];
745 if (childType->dispatch)
747 RemoveType(type + i, childType->typeSec.ident);
750 /* Link us into the free chain */
751 m_Types[++m_FreeTypes].freeID = type;
754 /* Invalidate the type now */
755 IHandleTypeDispatch *dispatch = pType->dispatch;
756 pType->dispatch = NULL;
758 /* Make sure nothing is using this type. */
762 for (unsigned int i=1; i<=m_HandleTail; i++)
764 pHandle = &m_Handles[i];
765 if (!pHandle->set || pHandle->type != type)
772 QHandle *pOther = &m_Handles[pHandle->clone];
773 if (--pOther->refcount == 0)
776 dispatch->OnHandleDestroy(type, pOther->object);
777 ReleasePrimHandle(pHandle->clone);
779 /* Unlink ourselves since we don't have a reference count */
780 ReleasePrimHandle(i);
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.
785 if (--pHandle->refcount == 0)
788 dispatch->OnHandleDestroy(type, pHandle->object);
789 ReleasePrimHandle(i);
792 if (pType->opened == 0)
802 bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
806 if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
810 pTypeAccess->access[HTypeAccess_Create] = false;
811 pTypeAccess->access[HTypeAccess_Inherit] = false;
812 pTypeAccess->ident = NULL;
817 if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
822 pHandleAccess->access[HandleAccess_Clone] = 0;
823 pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
824 pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;