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, HandleAccess_Read);
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);
42 HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch)
44 return CreateTypeEx(name, dispatch, 0, NULL, NULL);
47 HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch)
49 return CreateTypeEx(name, dispatch, parent, NULL, NULL);
52 HandleType_t HandleSystem::CreateTypeEx(const char *name,
53 IHandleTypeDispatch *dispatch,
55 const HandleSecurity *security,
56 IdentityToken_t *ident)
68 if (parent & HANDLESYS_SUBTYPE_MASK)
72 if (parent >= HANDLESYS_TYPEARRAY_SIZE
73 || m_Types[parent].dispatch == NULL
74 || (m_Types[parent].sec.access[HandleAccess_Inherit] == false
75 && m_Types[parent].sec.owner != ident))
85 security = &m_Types[parent].sec;
87 static HandleSecurity def_h;
92 if (security->access[HandleAccess_Create]
93 && sm_trie_retrieve(m_TypeLookup, name, NULL))
102 QHandleType *pParent = &m_Types[parent];
103 if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
108 for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
110 if (m_Types[parent + i].dispatch == NULL)
122 if (m_FreeTypes == 0)
124 /* Reserve another index */
125 if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
129 m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
133 /* The "free array" is compacted into the normal array for easiness */
134 index = m_Types[m_FreeTypes--].freeID;
138 QHandleType *pType = &m_Types[index];
140 pType->dispatch = dispatch;
141 if (name && name[0] != '\0')
143 pType->nameIdx = m_strtab->AddString(name);
144 sm_trie_insert(m_TypeLookup, name, (void *)pType);
148 pType->sec = *security;
159 bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
163 if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
168 unsigned int offset = _type - m_Types;
178 HandleError HandleSystem::MakePrimHandle(HandleType_t type,
179 QHandle **in_pHandle,
180 unsigned int *in_index,
182 IdentityToken_t *owner)
184 unsigned int owner_index = 0;
186 if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
188 return HandleError_Identity;
192 if (m_FreeHandles == 0)
194 if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
196 return HandleError_Limit;;
198 handle = ++m_HandleTail;
200 handle = m_Handles[m_FreeHandles--].freeID;
203 QHandle *pHandle = &m_Handles[handle];
205 assert(pHandle->set == false);
207 if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
212 /* Set essential information */
213 pHandle->set = HandleSet_Used;;
214 pHandle->refcount = 1;
215 pHandle->type = type;
216 pHandle->serial = m_HSerial;
217 pHandle->owner = owner;
218 pHandle->ch_next = 0;
220 /* Create the hash value */
221 Handle_t hash = pHandle->serial;
225 /* Add a reference count to the type */
226 m_Types[type].opened++;
229 *in_pHandle = pHandle;
233 /* Decode the identity token */
236 QHandle *pIdentity = &m_Handles[owner_index];
237 if (pIdentity->ch_prev == 0)
239 pIdentity->ch_prev = handle;
240 pIdentity->ch_next = handle;
241 pHandle->ch_prev = 0;
243 /* Link previous node to us (forward) */
244 m_Handles[pIdentity->ch_next].ch_next = handle;
245 /* Link us to previous node (backwards) */
246 pHandle->ch_prev = pIdentity->ch_next;
248 pIdentity->ch_next = handle;
250 pIdentity->refcount++;
252 pHandle->ch_prev = 0;
255 return HandleError_None;
258 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
261 || type >= HANDLESYS_TYPEARRAY_SIZE
262 || m_Types[type].dispatch == NULL)
267 m_Types[type].sec.owner = pToken;
270 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *source, IdentityToken_t *ident)
273 || type >= HANDLESYS_TYPEARRAY_SIZE
274 || m_Types[type].dispatch == NULL)
279 /* Check the security of this handle */
280 QHandleType *pType = &m_Types[type];
281 if (!pType->sec.access[HandleAccess_Create]
282 && pType->sec.owner != ident)
292 if ((err=MakePrimHandle(type, &pHandle, &index, &handle, source)) != HandleError_None)
297 pHandle->object = object;
303 Handle_t HandleSystem::CreateScriptHandle(HandleType_t type,
305 IPluginContext *pContext,
306 IdentityToken_t *ident)
308 IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
310 return CreateHandle(type, object, pPlugin->GetIdentity(), ident);
313 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
315 /* Check the type inheritance */
316 if (intype & HANDLESYS_SUBTYPE_MASK)
318 if (intype != outtype
319 && (TypeParent(intype) != TypeParent(outtype)))
324 if (intype != outtype)
333 HandleError HandleSystem::GetHandle(Handle_t handle,
334 IdentityToken_t *ident,
335 QHandle **in_pHandle,
336 unsigned int *in_index,
337 HandleAccessRight access)
339 unsigned int serial = (handle >> 16);
340 unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
342 if (index == 0 || index == 0xFFFF)
344 return HandleError_Index;
347 QHandle *pHandle = &m_Handles[index];
348 QHandleType *pType = &m_Types[pHandle->type];
350 if ((access != HandleAccess_TOTAL)
351 && (!pType->sec.access[access] && pType->sec.owner != ident))
353 return HandleError_Access;
357 return HandleError_Freed;
358 } else if (pHandle->set == HandleSet_Identity
359 && ident != g_ShareSys.GetIdentRoot())
361 /* Only IdentityHandle() can read this! */
362 return HandleError_Identity;
364 if (pHandle->serial != serial)
366 return HandleError_Changed;
369 *in_pHandle = pHandle;
372 return HandleError_None;
375 HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t *source, IdentityToken_t *ident)
381 if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Clone)) != HandleError_None)
386 QHandleType *pType = &m_Types[pHandle->type];
388 /* Get a new Handle ID */
389 unsigned int new_index;
393 if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, source)) != HandleError_None)
398 pNewHandle->clone = index;
402 *out_newhandle = new_handle;
405 return HandleError_None;
408 HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *ident)
414 if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Delete)) != HandleError_None)
419 QHandleType *pType = &m_Types[pHandle->type];
424 /* If we're a clone, there's not a lot to do. */
425 if (FreeHandle(pHandle->clone, ident) != HandleError_None)
431 if (--pHandle->refcount == 0)
434 pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
440 ReleasePrimHandle(index);
443 return HandleError_None;
446 HandleError HandleSystem::ReadHandle(Handle_t handle,
448 IdentityToken_t *ident,
455 if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Read)) != HandleError_None)
460 /* Check the type inheritance */
461 if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
463 if (pHandle->type != type
464 && (TypeParent(pHandle->type) != TypeParent(type)))
466 return HandleError_Type;
469 if (pHandle->type != type)
471 return HandleError_Type;
477 /* if we're a clone, the rules change - object is ONLY in our reference */
480 pHandle = &m_Handles[pHandle->clone];
482 *object = pHandle->object;
485 return HandleError_None;
488 void HandleSystem::ReleasePrimHandle(unsigned int index)
490 QHandle *pHandle = &m_Handles[index];
492 pHandle->set = HandleSet_None;
493 m_Types[pHandle->type].opened--;
494 m_Handles[++m_FreeHandles].freeID = index;
496 /* Unlink us if necessary */
499 unsigned int ident_index;
500 if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
503 assert(pHandle->owner == 0);
506 /* Note that since 0 is an invalid handle, if any of these links are 0,
507 * the data can still be set.
509 QHandle *pIdentity = &m_Handles[ident_index];
511 /* Unlink case: We're the head AND tail node */
512 if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
514 pIdentity->ch_prev = 0;
515 pIdentity->ch_next = 0;
517 /* Unlink case: We're the head node */
518 else if (index == pIdentity->ch_prev) {
519 /* Link us to the next in the chain */
520 pIdentity->ch_prev = pHandle->ch_next;
521 /* Patch up the previous link */
522 m_Handles[pHandle->ch_next].ch_prev = 0;
524 /* Unlink case: We're the tail node */
525 else if (index == pIdentity->ch_next) {
526 /* Link us to the previous in the chain */
527 pIdentity->ch_next = pHandle->ch_prev;
528 /* Patch up the next link */
529 m_Handles[pHandle->ch_prev].ch_next = 0;
531 /* Unlink case: We're in the middle! */
533 /* Patch the forward reference */
534 m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
535 /* Patch the backward reference */
536 m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
539 /* Lastly, decrease the reference count */
540 pIdentity->refcount--;
544 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
546 if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
551 QHandleType *pType = &m_Types[type];
553 if (pType->sec.owner && pType->sec.owner != ident)
558 if (pType->dispatch == NULL)
563 /* Remove children if we have to */
564 if (!(type & HANDLESYS_SUBTYPE_MASK))
566 QHandleType *childType;
567 for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
569 childType = &m_Types[type + i];
570 if (childType->dispatch)
572 RemoveType(type + i, childType->sec.owner);
575 /* Link us into the free chain */
576 m_Types[++m_FreeTypes].freeID = type;
579 /* Invalidate the type now */
580 IHandleTypeDispatch *dispatch = pType->dispatch;
581 pType->dispatch = NULL;
583 /* Make sure nothing is using this type. */
587 for (unsigned int i=1; i<m_HandleTail; i++)
589 pHandle = &m_Handles[i];
590 if (!pHandle->set || pHandle->type != type)
597 QHandle *pOther = &m_Handles[pHandle->clone];
598 if (--pOther->refcount == 0)
601 dispatch->OnHandleDestroy(type, pOther->object);
602 ReleasePrimHandle(pHandle->clone);
604 /* Unlink ourselves since we don't have a reference count */
605 ReleasePrimHandle(i);
607 /* If it's not a clone, we still have to check the reference count.
608 * Either way, we'll be destroyed eventually because the handle types do not change.
610 if (--pHandle->refcount == 0)
613 dispatch->OnHandleDestroy(type, pHandle->object);
614 ReleasePrimHandle(i);
617 if (pType->opened == 0)
627 void HandleSystem::MarkHandleAsIdentity(Handle_t handle)
632 if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index, HandleAccess_Read) != HandleError_None)
637 pHandle->set = HandleSet_Identity;