core/systems/HandleSys.cpp
author David Anderson <dvander@alliedmods.net>
Mon Aug 13 19:41:15 2007 +0000 (2007-08-13)
changeset 1321 a7c1296ca8d1
parent 1231 17badaf66ce4
child 1330 ab94316bb52b
permissions -rw-r--r--
fixed a bug where sm_dump_handles reported some freed handles incorrectly
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
dvander@1231
     3
 * ================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
dvander@1231
     6
 * ================================================================
dvander@370
     7
 *
dvander@1231
     8
 * This program is free software; you can redistribute it and/or 
dvander@1231
     9
 * modify it under the terms of the GNU General Public License, 
dvander@1231
    10
 * version 3.0, as published by the Free Software Foundation.
dvander@1231
    11
 * 
dvander@1231
    12
 * This program is distributed in the hope that it will be useful,
dvander@1231
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
dvander@1231
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dvander@1231
    15
 * GNU General Public License for more details.
dvander@1231
    16
 *
dvander@1231
    17
 * You should have received a copy of the GNU General Public License
dvander@1231
    18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
dvander@1231
    20
 * As a special exception, AlliedModders LLC gives you permission to 
dvander@1231
    21
 * link the code of this program (as well as its derivative works) to 
dvander@1231
    22
 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
dvander@1231
    23
 * Game MODs that run on software by the Valve Corporation.  You must 
dvander@1231
    24
 * obey the GNU General Public License in all respects for all other 
dvander@1231
    25
 * code used. Additionally, AlliedModders LLC grants this exception 
dvander@1231
    26
 * to all derivative works. AlliedModders LLC defines further 
dvander@1231
    27
 * exceptions, found in LICENSE.txt (as of this writing, version 
dvander@1231
    28
 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
dvander@370
    29
 *
dvander@370
    30
 * Version: $Id$
dvander@370
    31
 */
dvander@370
    32
dvander@218
    33
#include "HandleSys.h"
dvander@229
    34
#include "ShareSys.h"
dvander@218
    35
#include "PluginSys.h"
dvander@900
    36
#include "ExtensionSys.h"
dvander@222
    37
#include <assert.h>
dvander@351
    38
#include <string.h>
dvander@218
    39
dvander@218
    40
HandleSystem g_HandleSys;
dvander@218
    41
dvander@229
    42
QHandle *ignore_handle;
dvander@229
    43
dvander@229
    44
inline HandleType_t TypeParent(HandleType_t type)
dvander@229
    45
{
dvander@229
    46
	return (type & ~HANDLESYS_SUBTYPE_MASK);
dvander@229
    47
}
dvander@229
    48
dvander@229
    49
inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
dvander@229
    50
{
dvander@262
    51
	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
dvander@229
    52
}
dvander@229
    53
dvander@218
    54
HandleSystem::HandleSystem()
dvander@218
    55
{
dvander@218
    56
	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
dvander@218
    57
	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
dvander@218
    58
dvander@218
    59
	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
dvander@218
    60
	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
dvander@218
    61
dvander@218
    62
	m_TypeLookup = sm_trie_create();
dvander@218
    63
	m_strtab = new BaseStringTable(512);
dvander@218
    64
dvander@218
    65
	m_TypeTail = 0;
dvander@218
    66
}
dvander@218
    67
dvander@218
    68
HandleSystem::~HandleSystem()
dvander@218
    69
{
dvander@218
    70
	delete [] m_Handles;
dvander@218
    71
	delete [] m_Types;
dvander@218
    72
	sm_trie_destroy(m_TypeLookup);
dvander@218
    73
	delete m_strtab;
dvander@218
    74
}
dvander@218
    75
dvander@218
    76
dvander@262
    77
HandleType_t HandleSystem::CreateType(const char *name, 
dvander@262
    78
									  IHandleTypeDispatch *dispatch, 
dvander@262
    79
									  HandleType_t parent, 
dvander@262
    80
									  const TypeAccess *typeAccess, 
dvander@262
    81
									  const HandleAccess *hndlAccess, 
dvander@262
    82
									  IdentityToken_t *ident,
dvander@262
    83
									  HandleError *err)
dvander@218
    84
{
dvander@218
    85
	if (!dispatch)
dvander@218
    86
	{
dvander@262
    87
		if (err)
dvander@262
    88
		{
dvander@262
    89
			*err = HandleError_Parameter;
dvander@262
    90
		}
dvander@262
    91
		return 0;
dvander@262
    92
	}
dvander@262
    93
dvander@262
    94
	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
dvander@262
    95
	{
dvander@262
    96
		if (err)
dvander@262
    97
		{
dvander@262
    98
			*err = HandleError_Version;
dvander@262
    99
		}
dvander@262
   100
		return 0;
dvander@262
   101
	}
dvander@262
   102
dvander@262
   103
	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
dvander@262
   104
	{
dvander@262
   105
		if (err)
dvander@262
   106
		{
dvander@262
   107
			*err = HandleError_Version;
dvander@262
   108
		}
dvander@218
   109
		return 0;
dvander@218
   110
	}
dvander@218
   111
dvander@218
   112
	bool isChild = false;
dvander@218
   113
dvander@218
   114
	if (parent != 0)
dvander@218
   115
	{
dvander@218
   116
		isChild = true;
dvander@218
   117
		if (parent & HANDLESYS_SUBTYPE_MASK)
dvander@218
   118
		{
dvander@262
   119
			if (err)
dvander@262
   120
			{
dvander@262
   121
				*err = HandleError_NoInherit;
dvander@262
   122
			}
dvander@218
   123
			return 0;
dvander@218
   124
		}
dvander@218
   125
		if (parent >= HANDLESYS_TYPEARRAY_SIZE
dvander@262
   126
			|| m_Types[parent].dispatch == NULL)
dvander@218
   127
		{
dvander@262
   128
			if (err)
dvander@262
   129
			{
dvander@262
   130
				*err = HandleError_Parameter;
dvander@262
   131
			}
dvander@262
   132
			return 0;
dvander@262
   133
		}
dvander@262
   134
		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
dvander@262
   135
			&& (m_Types[parent].typeSec.ident != ident))
dvander@262
   136
		{
dvander@262
   137
			if (err)
dvander@262
   138
			{
dvander@262
   139
				*err = HandleError_Access;
dvander@262
   140
			}
dvander@218
   141
			return 0;
dvander@218
   142
		}
dvander@218
   143
	}
dvander@218
   144
dvander@262
   145
	if (name && name[0] != '\0')
dvander@218
   146
	{
dvander@262
   147
		if (sm_trie_retrieve(m_TypeLookup, name, NULL))
dvander@218
   148
		{
dvander@262
   149
			if (err)
dvander@262
   150
			{
dvander@262
   151
				*err = HandleError_Parameter;
dvander@262
   152
			}
dvander@262
   153
			return 0;
dvander@218
   154
		}
dvander@218
   155
	}
dvander@218
   156
dvander@218
   157
	unsigned int index;
dvander@218
   158
dvander@218
   159
	if (isChild)
dvander@218
   160
	{
dvander@218
   161
		QHandleType *pParent = &m_Types[parent];
dvander@218
   162
		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
dvander@218
   163
		{
dvander@262
   164
			if (err)
dvander@262
   165
			{
dvander@262
   166
				*err = HandleError_Limit;
dvander@262
   167
			}
dvander@218
   168
			return 0;
dvander@218
   169
		}
dvander@218
   170
		index = 0;
dvander@218
   171
		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
dvander@218
   172
		{
dvander@218
   173
			if (m_Types[parent + i].dispatch == NULL)
dvander@218
   174
			{
dvander@218
   175
				index = parent + i;
dvander@218
   176
				break;
dvander@218
   177
			}
dvander@218
   178
		}
dvander@218
   179
		if (!index)
dvander@218
   180
		{
dvander@262
   181
			if (err)
dvander@262
   182
			{
dvander@262
   183
				*err = HandleError_Limit;
dvander@262
   184
			}
dvander@218
   185
			return 0;
dvander@218
   186
		}
dvander@218
   187
		pParent->children++;
dvander@218
   188
	} else {
dvander@218
   189
		if (m_FreeTypes == 0)
dvander@218
   190
		{
dvander@218
   191
			/* Reserve another index */
dvander@218
   192
			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
dvander@218
   193
			{
dvander@262
   194
				if (err)
dvander@262
   195
				{
dvander@262
   196
					*err = HandleError_Limit;
dvander@262
   197
				}
dvander@218
   198
				return 0;
dvander@218
   199
			} else {
dvander@218
   200
				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
dvander@218
   201
				index = m_TypeTail;
dvander@218
   202
			}
dvander@218
   203
		} else {
dvander@218
   204
			/* The "free array" is compacted into the normal array for easiness */
dvander@218
   205
			index = m_Types[m_FreeTypes--].freeID;
dvander@218
   206
		}
dvander@218
   207
	}
dvander@218
   208
dvander@218
   209
	QHandleType *pType = &m_Types[index];
dvander@218
   210
	
dvander@218
   211
	pType->dispatch = dispatch;
dvander@218
   212
	if (name && name[0] != '\0')
dvander@218
   213
	{
dvander@218
   214
		pType->nameIdx = m_strtab->AddString(name);
dvander@218
   215
		sm_trie_insert(m_TypeLookup, name, (void *)pType);
dvander@218
   216
	} else {
dvander@218
   217
		pType->nameIdx = -1;
dvander@218
   218
	}
dvander@262
   219
dvander@218
   220
	pType->opened = 0;
dvander@218
   221
dvander@262
   222
	if (typeAccess)
dvander@262
   223
	{
dvander@262
   224
		pType->typeSec = *typeAccess;
dvander@262
   225
	} else {
dvander@262
   226
		InitAccessDefaults(&pType->typeSec, NULL);
dvander@262
   227
		pType->typeSec.ident = ident;
dvander@262
   228
	}
dvander@262
   229
dvander@262
   230
	if (hndlAccess)
dvander@262
   231
	{
dvander@262
   232
		pType->hndlSec = *hndlAccess;
dvander@262
   233
	} else {
dvander@262
   234
		InitAccessDefaults(NULL, &pType->hndlSec);
dvander@262
   235
	}
dvander@262
   236
dvander@218
   237
	if (!isChild)
dvander@218
   238
	{
dvander@218
   239
		pType->children = 0;
dvander@218
   240
	}
dvander@218
   241
dvander@218
   242
	return index;
dvander@218
   243
}
dvander@218
   244
dvander@218
   245
bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
dvander@218
   246
{
dvander@218
   247
	QHandleType *_type;
dvander@218
   248
dvander@218
   249
	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
dvander@218
   250
	{
dvander@218
   251
		return false;
dvander@218
   252
	}
dvander@218
   253
dvander@218
   254
	unsigned int offset = _type - m_Types;
dvander@218
   255
dvander@218
   256
	if (type)
dvander@218
   257
	{
dvander@218
   258
		*type = offset;
dvander@218
   259
	}
dvander@218
   260
dvander@218
   261
	return true;
dvander@218
   262
}
dvander@218
   263
dvander@222
   264
HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
dvander@222
   265
						   QHandle **in_pHandle, 
dvander@222
   266
						   unsigned int *in_index, 
dvander@229
   267
						   Handle_t *in_handle,
dvander@283
   268
						   IdentityToken_t *owner,
dvander@283
   269
						   bool identity)
dvander@222
   270
{
dvander@229
   271
	unsigned int owner_index = 0;
dvander@229
   272
dvander@229
   273
	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
dvander@229
   274
	{
dvander@229
   275
		return HandleError_Identity;
dvander@229
   276
	}
dvander@229
   277
dvander@222
   278
	unsigned int handle;
dvander@222
   279
	if (m_FreeHandles == 0)
dvander@222
   280
	{
dvander@222
   281
		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
dvander@222
   282
		{
dvander@222
   283
			return HandleError_Limit;;
dvander@222
   284
		}
dvander@222
   285
		handle = ++m_HandleTail;
dvander@222
   286
	} else {
dvander@222
   287
		handle = m_Handles[m_FreeHandles--].freeID;
dvander@222
   288
	}
dvander@222
   289
dvander@222
   290
	QHandle *pHandle = &m_Handles[handle];
dvander@222
   291
	
dvander@222
   292
	assert(pHandle->set == false);
dvander@222
   293
dvander@222
   294
	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
dvander@222
   295
	{
dvander@222
   296
		m_HSerial = 1;
dvander@222
   297
	}
dvander@222
   298
dvander@222
   299
	/* Set essential information */
dvander@283
   300
	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
dvander@222
   301
	pHandle->refcount = 1;
dvander@222
   302
	pHandle->type = type;
dvander@222
   303
	pHandle->serial = m_HSerial;
dvander@229
   304
	pHandle->owner = owner;
dvander@229
   305
	pHandle->ch_next = 0;
dvander@528
   306
	pHandle->access_special = false;
dvander@789
   307
	pHandle->is_destroying = false;
dvander@222
   308
dvander@222
   309
	/* Create the hash value */
dvander@222
   310
	Handle_t hash = pHandle->serial;
dvander@222
   311
	hash <<= 16;
dvander@222
   312
	hash |= handle;
dvander@222
   313
dvander@222
   314
	/* Add a reference count to the type */
dvander@222
   315
	m_Types[type].opened++;
dvander@222
   316
dvander@222
   317
	/* Output */
dvander@222
   318
	*in_pHandle = pHandle;
dvander@222
   319
	*in_index = handle;
dvander@222
   320
	*in_handle = hash;
dvander@222
   321
dvander@283
   322
	/* Decode the identity token 
dvander@283
   323
	 * For now, we don't allow nested ownership
dvander@283
   324
	 */
dvander@283
   325
	if (owner && !identity)
dvander@229
   326
	{
dvander@229
   327
		QHandle *pIdentity = &m_Handles[owner_index];
dvander@229
   328
		if (pIdentity->ch_prev == 0)
dvander@229
   329
		{
dvander@229
   330
			pIdentity->ch_prev = handle;
dvander@229
   331
			pIdentity->ch_next = handle;
dvander@229
   332
			pHandle->ch_prev = 0;
dvander@229
   333
		} else {
dvander@229
   334
			/* Link previous node to us (forward) */
dvander@229
   335
			m_Handles[pIdentity->ch_next].ch_next = handle;
dvander@229
   336
			/* Link us to previous node (backwards) */
dvander@229
   337
			pHandle->ch_prev = pIdentity->ch_next;
dvander@229
   338
			/* Set new tail */
dvander@229
   339
			pIdentity->ch_next = handle;
dvander@229
   340
		}
dvander@229
   341
		pIdentity->refcount++;
dvander@229
   342
	} else {
dvander@229
   343
		pHandle->ch_prev = 0;
dvander@229
   344
	}
dvander@229
   345
dvander@222
   346
	return HandleError_None;
dvander@222
   347
}
dvander@222
   348
dvander@229
   349
void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
dvander@229
   350
{
dvander@229
   351
	if (!type
dvander@229
   352
		|| type >= HANDLESYS_TYPEARRAY_SIZE
dvander@229
   353
		|| m_Types[type].dispatch == NULL)
dvander@229
   354
	{
dvander@229
   355
		return;
dvander@229
   356
	}
dvander@229
   357
dvander@262
   358
	m_Types[type].typeSec.ident = pToken;
dvander@229
   359
}
dvander@229
   360
dvander@528
   361
Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
dvander@528
   362
									   void *object, 
dvander@528
   363
									   const HandleSecurity *pSec,
dvander@528
   364
									   HandleError *err, 
dvander@528
   365
									   const HandleAccess *pAccess,
dvander@528
   366
									   bool identity)
dvander@218
   367
{
dvander@528
   368
	IdentityToken_t *ident;
dvander@528
   369
	IdentityToken_t *owner;
dvander@528
   370
dvander@528
   371
	if (pSec)
dvander@528
   372
	{
dvander@528
   373
		ident = pSec->pIdentity;
dvander@528
   374
		owner = pSec->pOwner;
dvander@528
   375
	} else {
dvander@528
   376
		ident = NULL;
dvander@528
   377
		owner = NULL;
dvander@528
   378
	}
dvander@528
   379
dvander@218
   380
	if (!type 
dvander@218
   381
		|| type >= HANDLESYS_TYPEARRAY_SIZE
dvander@218
   382
		|| m_Types[type].dispatch == NULL)
dvander@218
   383
	{
dvander@262
   384
		if (err)
dvander@262
   385
		{
dvander@262
   386
			*err = HandleError_Parameter;
dvander@262
   387
		}
dvander@218
   388
		return 0;
dvander@218
   389
	}
dvander@218
   390
dvander@262
   391
	/* Check to see if we're allowed to create this handle type */
dvander@218
   392
	QHandleType *pType = &m_Types[type];
dvander@262
   393
	if (!pType->typeSec.access[HTypeAccess_Create]
dvander@283
   394
	&& (!pType->typeSec.ident
dvander@283
   395
		|| pType->typeSec.ident != ident))
dvander@218
   396
	{
dvander@262
   397
		if (err)
dvander@262
   398
		{
dvander@262
   399
			*err = HandleError_Access;
dvander@262
   400
		}
dvander@218
   401
		return 0;
dvander@218
   402
	}
dvander@218
   403
dvander@222
   404
	unsigned int index;
dvander@222
   405
	Handle_t handle;
dvander@222
   406
	QHandle *pHandle;
dvander@262
   407
	HandleError _err;
dvander@222
   408
dvander@283
   409
	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
dvander@218
   410
	{
dvander@262
   411
		if (err)
dvander@262
   412
		{
dvander@262
   413
			*err = _err;
dvander@262
   414
		}
dvander@222
   415
		return 0;
dvander@218
   416
	}
dvander@218
   417
dvander@528
   418
	if (pAccess)
dvander@528
   419
	{
dvander@528
   420
		pHandle->access_special = true;
dvander@528
   421
		pHandle->sec = *pAccess;
dvander@528
   422
	}
dvander@528
   423
dvander@218
   424
	pHandle->object = object;
dvander@222
   425
	pHandle->clone = 0;
dvander@218
   426
dvander@222
   427
	return handle;
dvander@218
   428
}
dvander@218
   429
dvander@528
   430
Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
dvander@528
   431
{
dvander@528
   432
	return CreateHandleInt(type, object, pSec, err, pAccess, false);
dvander@528
   433
}
dvander@528
   434
dvander@283
   435
Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
dvander@283
   436
{
dvander@528
   437
	HandleSecurity sec;
dvander@528
   438
dvander@528
   439
	sec.pIdentity = ident;
dvander@528
   440
	sec.pOwner = owner;
dvander@528
   441
dvander@528
   442
	return CreateHandleEx(type, object, &sec, NULL, err);
dvander@283
   443
}
dvander@283
   444
dvander@229
   445
bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
dvander@229
   446
{
dvander@229
   447
	/* Check the type inheritance */
dvander@229
   448
	if (intype & HANDLESYS_SUBTYPE_MASK)
dvander@229
   449
	{
dvander@229
   450
		if (intype != outtype
dvander@229
   451
			&& (TypeParent(intype) != TypeParent(outtype)))
dvander@229
   452
		{
dvander@229
   453
			return false;
dvander@229
   454
		}
dvander@229
   455
	} else {
dvander@229
   456
		if (intype != outtype)
dvander@229
   457
		{
dvander@229
   458
			return false;
dvander@229
   459
		}
dvander@229
   460
	}
dvander@229
   461
dvander@229
   462
	return true;
dvander@229
   463
}
dvander@229
   464
dvander@222
   465
HandleError HandleSystem::GetHandle(Handle_t handle,
dvander@229
   466
									IdentityToken_t *ident, 
dvander@222
   467
									QHandle **in_pHandle, 
dvander@222
   468
									unsigned int *in_index,
dvander@259
   469
									bool ignoreFree)
dvander@218
   470
{
dvander@218
   471
	unsigned int serial = (handle >> 16);
dvander@218
   472
	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
dvander@218
   473
dvander@218
   474
	if (index == 0 || index == 0xFFFF)
dvander@218
   475
	{
dvander@218
   476
		return HandleError_Index;
dvander@218
   477
	}
dvander@218
   478
dvander@218
   479
	QHandle *pHandle = &m_Handles[index];
dvander@218
   480
dvander@259
   481
	if (!pHandle->set
dvander@259
   482
		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
dvander@218
   483
	{
dvander@218
   484
		return HandleError_Freed;
dvander@229
   485
	} else if (pHandle->set == HandleSet_Identity
dvander@229
   486
			   && ident != g_ShareSys.GetIdentRoot())
dvander@229
   487
	{
dvander@229
   488
		/* Only IdentityHandle() can read this! */
dvander@229
   489
		return HandleError_Identity;
dvander@218
   490
	}
dvander@218
   491
	if (pHandle->serial != serial)
dvander@218
   492
	{
dvander@218
   493
		return HandleError_Changed;
dvander@218
   494
	}
dvander@218
   495
dvander@222
   496
	*in_pHandle = pHandle;
dvander@222
   497
	*in_index = index;
dvander@222
   498
dvander@222
   499
	return HandleError_None;
dvander@222
   500
}
dvander@222
   501
dvander@262
   502
bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
dvander@262
   503
{
dvander@262
   504
	QHandleType *pType = &m_Types[pHandle->type];
dvander@528
   505
	unsigned int access;
dvander@528
   506
dvander@528
   507
	if (pHandle->access_special)
dvander@528
   508
	{
dvander@528
   509
		access = pHandle->sec.access[right];
dvander@528
   510
	} else {
dvander@528
   511
		access = pType->hndlSec.access[right];
dvander@528
   512
	}
dvander@262
   513
dvander@262
   514
	/* Check if the type's identity matches */
dvander@262
   515
	if (access & HANDLE_RESTRICT_IDENTITY)
dvander@262
   516
	{
dvander@262
   517
		IdentityToken_t *owner = pType->typeSec.ident;
dvander@262
   518
		if (!owner
dvander@262
   519
			|| (!pSecurity || pSecurity->pIdentity != owner))
dvander@262
   520
		{
dvander@262
   521
			return false;
dvander@262
   522
		}
dvander@262
   523
	}
dvander@262
   524
dvander@262
   525
	/* Check if the owner is allowed */
dvander@262
   526
	if (access & HANDLE_RESTRICT_OWNER)
dvander@262
   527
	{
dvander@262
   528
		IdentityToken_t *owner = pHandle->owner;
dvander@262
   529
		if (owner
dvander@262
   530
			&& (!pSecurity || pSecurity->pOwner != owner))
dvander@262
   531
		{
dvander@262
   532
			return false;
dvander@262
   533
		}
dvander@262
   534
	}
dvander@262
   535
dvander@262
   536
	return true;
dvander@262
   537
}
dvander@262
   538
dvander@283
   539
HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
dvander@283
   540
{
dvander@283
   541
	/* Get a new Handle ID */
dvander@283
   542
	unsigned int new_index;
dvander@283
   543
	QHandle *pNewHandle;
dvander@283
   544
	Handle_t new_handle;
dvander@283
   545
	HandleError err;
dvander@283
   546
dvander@283
   547
	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
dvander@283
   548
	{
dvander@283
   549
		return err;
dvander@283
   550
	}
dvander@283
   551
dvander@528
   552
	/* Assign permissions from parent */
dvander@528
   553
	if (pHandle->access_special)
dvander@528
   554
	{
dvander@528
   555
		pNewHandle->access_special = true;
dvander@528
   556
		pNewHandle->sec = pHandle->sec;
dvander@528
   557
	}
dvander@528
   558
dvander@283
   559
	pNewHandle->clone = index;
dvander@283
   560
	pHandle->refcount++;
dvander@283
   561
dvander@283
   562
	*newhandle = new_handle;
dvander@283
   563
dvander@283
   564
	return HandleError_None;
dvander@283
   565
}
dvander@283
   566
dvander@262
   567
HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
dvander@222
   568
{
dvander@222
   569
	HandleError err;
dvander@222
   570
	QHandle *pHandle;
dvander@222
   571
	unsigned int index;
dvander@262
   572
	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
dvander@222
   573
dvander@262
   574
	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
dvander@222
   575
	{
dvander@222
   576
		return err;
dvander@222
   577
	}
dvander@222
   578
dvander@259
   579
	/* Identities cannot be cloned */
dvander@259
   580
	if (pHandle->set == HandleSet_Identity)
dvander@259
   581
	{
dvander@259
   582
		return HandleError_Identity;
dvander@259
   583
	}
dvander@259
   584
dvander@262
   585
	/* Check if the handle can be cloned */
dvander@262
   586
	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
dvander@262
   587
	{
dvander@262
   588
		return HandleError_Access;
dvander@262
   589
	}
dvander@222
   590
dvander@283
   591
	/* Make sure we're not cloning a clone */
dvander@283
   592
	if (pHandle->clone)
dvander@222
   593
	{
dvander@283
   594
		QHandle *pParent = &m_Handles[pHandle->clone];
dvander@283
   595
		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
dvander@222
   596
	}
dvander@222
   597
dvander@283
   598
	return CloneHandle(pHandle, index, newhandle, newOwner);
dvander@283
   599
}
dvander@283
   600
dvander@283
   601
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
dvander@283
   602
{
dvander@283
   603
	QHandleType *pType = &m_Types[pHandle->type];
dvander@283
   604
dvander@283
   605
	if (pHandle->clone)
dvander@283
   606
	{
dvander@283
   607
		/* If we're a clone, decrease the parent reference count */
dvander@283
   608
		QHandle *pMaster;
dvander@283
   609
		unsigned int master;
dvander@283
   610
dvander@283
   611
		/* Note that if we ever have per-handle security, we would need to re-check
dvander@283
   612
		* the access on this Handle. */
dvander@283
   613
		master = pHandle->clone;
dvander@283
   614
		pMaster = &m_Handles[master];
dvander@283
   615
dvander@283
   616
		/* Release the clone now */
dvander@283
   617
		ReleasePrimHandle(index);
dvander@222
   618
dvander@283
   619
		/* Decrement the master's reference count */
dvander@283
   620
		if (--pMaster->refcount == 0)
dvander@283
   621
		{
dvander@283
   622
			/* Type should be the same but do this anyway... */
dvander@283
   623
			pType = &m_Types[pMaster->type];
dvander@789
   624
			pMaster->is_destroying = true;
dvander@283
   625
			pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
dvander@283
   626
			ReleasePrimHandle(master);
dvander@283
   627
		}
dvander@283
   628
	} else if (pHandle->set == HandleSet_Identity) {
dvander@283
   629
		/* If we're an identity, skip all this stuff!
dvander@283
   630
		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
dvander@283
   631
		 */
dvander@283
   632
		ReleasePrimHandle(index);
dvander@283
   633
	} else {
dvander@283
   634
		/* Decrement, free if necessary */
dvander@283
   635
		if (--pHandle->refcount == 0)
dvander@283
   636
		{
dvander@789
   637
			pHandle->is_destroying = true;
dvander@283
   638
			pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
dvander@283
   639
			ReleasePrimHandle(index);
dvander@283
   640
		} else {
dvander@283
   641
			/* We must be cloned, so mark ourselves as freed */
dvander@283
   642
			pHandle->set = HandleSet_Freed;
dvander@283
   643
			/* Now, unlink us, so we're not being tracked by the owner */
dvander@283
   644
			if (pHandle->owner)
dvander@283
   645
			{
dvander@283
   646
				UnlinkHandleFromOwner(pHandle, index);
dvander@283
   647
			}
dvander@283
   648
		}
dvander@283
   649
	}
dvander@222
   650
dvander@222
   651
	return HandleError_None;
dvander@222
   652
}
dvander@222
   653
dvander@262
   654
HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
dvander@222
   655
{
dvander@222
   656
	unsigned int index;
dvander@222
   657
	QHandle *pHandle;
dvander@222
   658
	HandleError err;
dvander@262
   659
	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
dvander@222
   660
dvander@262
   661
	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
dvander@222
   662
	{
dvander@222
   663
		return err;
dvander@222
   664
	}
dvander@222
   665
dvander@262
   666
	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
dvander@259
   667
	{
dvander@259
   668
		return HandleError_Access;
dvander@259
   669
	}
dvander@259
   670
dvander@789
   671
	if (pHandle->is_destroying)
dvander@789
   672
	{
dvander@789
   673
		/* Someone tried to free this recursively.  
dvander@789
   674
		 * We'll just ignore this safely.
dvander@789
   675
		 */
dvander@789
   676
		return HandleError_None;
dvander@789
   677
	}
dvander@789
   678
dvander@283
   679
	return FreeHandle(pHandle, index);
dvander@218
   680
}
dvander@218
   681
dvander@262
   682
HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
dvander@218
   683
{
dvander@222
   684
	unsigned int index;
dvander@222
   685
	QHandle *pHandle;
dvander@222
   686
	HandleError err;
dvander@262
   687
	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
dvander@218
   688
dvander@262
   689
	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
dvander@218
   690
	{
dvander@222
   691
		return err;
dvander@218
   692
	}
dvander@218
   693
dvander@262
   694
	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
dvander@262
   695
	{
dvander@262
   696
		return HandleError_Access;
dvander@262
   697
	}
dvander@262
   698
dvander@218
   699
	/* Check the type inheritance */
dvander@218
   700
	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
dvander@218
   701
	{
dvander@218
   702
		if (pHandle->type != type
dvander@218
   703
			&& (TypeParent(pHandle->type) != TypeParent(type)))
dvander@218
   704
		{
dvander@218
   705
			return HandleError_Type;
dvander@218
   706
		}
dvander@247
   707
	} else if (type) {
dvander@218
   708
		if (pHandle->type != type)
dvander@218
   709
		{
dvander@218
   710
			return HandleError_Type;
dvander@218
   711
		}
dvander@218
   712
	}
dvander@218
   713
dvander@218
   714
	if (object)
dvander@218
   715
	{
dvander@222
   716
		/* if we're a clone, the rules change - object is ONLY in our reference */
dvander@222
   717
		if (pHandle->clone)
dvander@222
   718
		{
dvander@262
   719
			pHandle = &m_Handles[pHandle->clone];
dvander@222
   720
		}
dvander@218
   721
		*object = pHandle->object;
dvander@218
   722
	}
dvander@218
   723
dvander@218
   724
	return HandleError_None;
dvander@218
   725
}
dvander@218
   726
dvander@283
   727
void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
dvander@283
   728
{
dvander@283
   729
	/* Unlink us if necessary */
dvander@283
   730
	unsigned int ident_index;
dvander@283
   731
	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
dvander@283
   732
	{
dvander@283
   733
		/* Uh-oh! */
dvander@283
   734
		assert(pHandle->owner == 0);
dvander@283
   735
		return;
dvander@283
   736
	}
dvander@283
   737
	/* Note that since 0 is an invalid handle, if any of these links are 0,
dvander@283
   738
	* the data can still be set.
dvander@283
   739
	*/
dvander@283
   740
	QHandle *pIdentity = &m_Handles[ident_index];
dvander@283
   741
dvander@283
   742
	/* Unlink case: We're the head AND tail node */
dvander@283
   743
	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
dvander@283
   744
	{
dvander@283
   745
		pIdentity->ch_prev = 0;
dvander@283
   746
		pIdentity->ch_next = 0;
dvander@283
   747
	}
dvander@283
   748
	/* Unlink case: We're the head node */
dvander@283
   749
	else if (index == pIdentity->ch_prev) {
dvander@283
   750
		/* Link us to the next in the chain */
dvander@283
   751
		pIdentity->ch_prev = pHandle->ch_next;
dvander@283
   752
		/* Patch up the previous link */
dvander@283
   753
		m_Handles[pHandle->ch_next].ch_prev = 0;
dvander@283
   754
	}
dvander@283
   755
	/* Unlink case: We're the tail node */
dvander@283
   756
	else if (index == pIdentity->ch_next) {
dvander@283
   757
		/* Link us to the previous in the chain */
dvander@283
   758
		pIdentity->ch_next = pHandle->ch_prev;
dvander@283
   759
		/* Patch up the next link */
dvander@283
   760
		m_Handles[pHandle->ch_prev].ch_next = 0;
dvander@283
   761
	}
dvander@283
   762
	/* Unlink case: We're in the middle! */
dvander@283
   763
	else {
dvander@283
   764
		/* Patch the forward reference */
dvander@283
   765
		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
dvander@283
   766
		/* Patch the backward reference */
dvander@283
   767
		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
dvander@283
   768
	}
dvander@283
   769
dvander@283
   770
	/* Lastly, decrease the reference count */
dvander@283
   771
	pIdentity->refcount--;
dvander@283
   772
}
dvander@283
   773
dvander@222
   774
void HandleSystem::ReleasePrimHandle(unsigned int index)
dvander@222
   775
{
dvander@222
   776
	QHandle *pHandle = &m_Handles[index];
dvander@283
   777
	HandleSet set = pHandle->set;
dvander@283
   778
dvander@283
   779
	if (pHandle->owner && (set != HandleSet_Identity))
dvander@283
   780
	{
dvander@283
   781
		UnlinkHandleFromOwner(pHandle, index);
dvander@283
   782
	}
dvander@283
   783
dvander@283
   784
	/* Were we an identity ourself? */
dvander@283
   785
	QHandle *pLocal;
dvander@283
   786
	if (set == HandleSet_Identity)
dvander@283
   787
	{
dvander@283
   788
		/* Extra work to do.  We need to find everything connected to this identity and release it. */
dvander@351
   789
		unsigned int ch_index;
dvander@364
   790
#if defined _DEBUG
dvander@364
   791
		unsigned int old_index = 0;
dvander@364
   792
#endif
dvander@283
   793
		while ((ch_index = pHandle->ch_next) != 0)
dvander@283
   794
		{
dvander@283
   795
			pLocal = &m_Handles[ch_index];
dvander@283
   796
#if defined _DEBUG
dvander@283
   797
			assert(old_index != ch_index);
dvander@283
   798
			assert(pLocal->set == HandleSet_Used);
dvander@283
   799
			old_index = ch_index;
dvander@283
   800
#endif
dvander@283
   801
			FreeHandle(pLocal, ch_index);
dvander@283
   802
		}
dvander@283
   803
	}
dvander@283
   804
dvander@229
   805
	pHandle->set = HandleSet_None;
dvander@222
   806
	m_Types[pHandle->type].opened--;
dvander@222
   807
	m_Handles[++m_FreeHandles].freeID = index;
dvander@222
   808
}
dvander@222
   809
dvander@229
   810
bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
dvander@218
   811
{
dvander@218
   812
	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
dvander@218
   813
	{
dvander@218
   814
		return false;
dvander@218
   815
	}
dvander@218
   816
dvander@218
   817
	QHandleType *pType = &m_Types[type];
dvander@218
   818
dvander@262
   819
	if (pType->typeSec.ident
dvander@262
   820
		&& pType->typeSec.ident != ident)
dvander@218
   821
	{
dvander@218
   822
		return false;
dvander@218
   823
	}
dvander@218
   824
dvander@218
   825
	if (pType->dispatch == NULL)
dvander@218
   826
	{
dvander@218
   827
		return false;
dvander@218
   828
	}
dvander@218
   829
dvander@218
   830
	/* Remove children if we have to */
dvander@218
   831
	if (!(type & HANDLESYS_SUBTYPE_MASK))
dvander@218
   832
	{
dvander@218
   833
		QHandleType *childType;
dvander@218
   834
		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
dvander@218
   835
		{
dvander@218
   836
			childType = &m_Types[type + i];
dvander@218
   837
			if (childType->dispatch)
dvander@218
   838
			{
dvander@262
   839
				RemoveType(type + i, childType->typeSec.ident);
dvander@218
   840
			}
dvander@218
   841
		}
dvander@218
   842
		/* Link us into the free chain */
dvander@218
   843
		m_Types[++m_FreeTypes].freeID = type;
dvander@218
   844
	}
dvander@218
   845
dvander@218
   846
	/* Invalidate the type now */
dvander@218
   847
	IHandleTypeDispatch *dispatch = pType->dispatch;
dvander@218
   848
	pType->dispatch = NULL;
dvander@218
   849
dvander@218
   850
	/* Make sure nothing is using this type. */
dvander@218
   851
	if (pType->opened)
dvander@218
   852
	{
dvander@218
   853
		QHandle *pHandle;
dvander@297
   854
		for (unsigned int i=1; i<=m_HandleTail; i++)
dvander@218
   855
		{
dvander@218
   856
			pHandle = &m_Handles[i];
dvander@218
   857
			if (!pHandle->set || pHandle->type != type)
dvander@218
   858
			{
dvander@218
   859
				continue;
dvander@218
   860
			}
dvander@222
   861
			if (pHandle->clone)
dvander@222
   862
			{
dvander@222
   863
				/* Get parent */
dvander@222
   864
				QHandle *pOther = &m_Handles[pHandle->clone];
dvander@222
   865
				if (--pOther->refcount == 0)
dvander@222
   866
				{
dvander@222
   867
					/* Free! */
dvander@222
   868
					dispatch->OnHandleDestroy(type, pOther->object);
dvander@222
   869
					ReleasePrimHandle(pHandle->clone);
dvander@222
   870
				}
dvander@222
   871
				/* Unlink ourselves since we don't have a reference count */
dvander@222
   872
				ReleasePrimHandle(i);
dvander@222
   873
			} else {
dvander@222
   874
				/* If it's not a clone, we still have to check the reference count.
dvander@222
   875
				 * Either way, we'll be destroyed eventually because the handle types do not change.
dvander@222
   876
				 */
dvander@222
   877
				if (--pHandle->refcount == 0)
dvander@222
   878
				{
dvander@222
   879
					/* Free! */
dvander@222
   880
					dispatch->OnHandleDestroy(type, pHandle->object);
dvander@222
   881
					ReleasePrimHandle(i);
dvander@222
   882
				}
dvander@222
   883
			}
dvander@222
   884
			if (pType->opened == 0)
dvander@218
   885
			{
dvander@218
   886
				break;
dvander@218
   887
			}
dvander@218
   888
		}
dvander@218
   889
	}
dvander@218
   890
dvander@218
   891
	return true;
dvander@218
   892
}
dvander@229
   893
dvander@262
   894
bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
dvander@262
   895
{
dvander@262
   896
	if (pTypeAccess)
dvander@262
   897
	{
dvander@262
   898
		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
dvander@262
   899
		{
dvander@262
   900
			return false;
dvander@262
   901
		}
dvander@262
   902
		pTypeAccess->access[HTypeAccess_Create] = false;
dvander@262
   903
		pTypeAccess->access[HTypeAccess_Inherit] = false;
dvander@262
   904
		pTypeAccess->ident = NULL;
dvander@262
   905
	}
dvander@262
   906
dvander@262
   907
	if (pHandleAccess)
dvander@262
   908
	{
dvander@262
   909
		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
dvander@262
   910
		{
dvander@262
   911
			return false;
dvander@262
   912
		}
dvander@262
   913
dvander@262
   914
		pHandleAccess->access[HandleAccess_Clone] = 0;
dvander@262
   915
		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
dvander@262
   916
		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
dvander@262
   917
	}
dvander@262
   918
dvander@262
   919
	return true;
dvander@262
   920
}
dvander@900
   921
dvander@900
   922
void HandleSystem::Dump(FILE *fp)
dvander@900
   923
{
dvander@900
   924
	fprintf(fp, "%-10.10s\t%-20.20s\t%-20.20s\n", "Handle", "Owner", "Type");
dvander@900
   925
	fprintf(fp, "---------------------------------------------\n");
dvander@900
   926
	for (unsigned int i=1; i<=m_HandleTail; i++)
dvander@900
   927
	{
dvander@1321
   928
		if (m_Handles[i].set != HandleSet_Used)
dvander@900
   929
		{
dvander@900
   930
			continue;
dvander@900
   931
		}
dvander@900
   932
		/* Get the index */
dvander@900
   933
		unsigned int index = (m_Handles[i].serial << 16) | i;
dvander@900
   934
		/* Determine the owner */
dvander@900
   935
		const char *owner = "UNKNOWN";
dvander@900
   936
		if (m_Handles[i].owner)
dvander@900
   937
		{
dvander@900
   938
			IdentityToken_t *pOwner = m_Handles[i].owner;
dvander@900
   939
			if (pOwner == g_pCoreIdent)
dvander@900
   940
			{
dvander@900
   941
				owner = "CORE";
dvander@900
   942
			} else if (pOwner == g_PluginSys.GetIdentity()) {
dvander@900
   943
				owner = "PLUGINSYS";
dvander@900
   944
			} else {
dvander@900
   945
				CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
dvander@900
   946
				if (ext)
dvander@900
   947
				{
dvander@900
   948
					owner = ext->GetFilename();
dvander@900
   949
				} else {
dvander@900
   950
					CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
dvander@900
   951
					if (pPlugin)
dvander@900
   952
					{
dvander@900
   953
						owner = pPlugin->GetFilename();
dvander@900
   954
					}
dvander@900
   955
				}
dvander@900
   956
			}
dvander@900
   957
		} else {
dvander@900
   958
			owner = "NONE";
dvander@900
   959
		}
dvander@900
   960
		const char *type = "ANON";
dvander@900
   961
		QHandleType *pType = &m_Types[m_Handles[i].type];
dvander@900
   962
		if (pType->nameIdx != -1)
dvander@900
   963
		{
dvander@900
   964
			type = m_strtab->GetString(pType->nameIdx);
dvander@900
   965
		}
dvander@900
   966
		fprintf(fp, "0x%08x\t%-20.20s\t%-20.20s\n", index, owner, type);
dvander@900
   967
	}
dvander@900
   968
}