resource.c revision 05b261ec
1/************************************************************ 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46********************************************************/ 47/* The panoramix components contained the following notice */ 48/***************************************************************** 49 50Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. 51 52Permission is hereby granted, free of charge, to any person obtaining a copy 53of this software and associated documentation files (the "Software"), to deal 54in the Software without restriction, including without limitation the rights 55to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 56copies of the Software. 57 58The above copyright notice and this permission notice shall be included in 59all copies or substantial portions of the Software. 60 61THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 64DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 65BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 66WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 67IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 68 69Except as contained in this notice, the name of Digital Equipment Corporation 70shall not be used in advertising or otherwise to promote the sale, use or other 71dealings in this Software without prior written authorization from Digital 72Equipment Corporation. 73 74******************************************************************/ 75/* XSERVER_DTRACE additions: 76 * Copyright 2005-2006 Sun Microsystems, Inc. All rights reserved. 77 * 78 * Permission is hereby granted, free of charge, to any person obtaining a 79 * copy of this software and associated documentation files (the 80 * "Software"), to deal in the Software without restriction, including 81 * without limitation the rights to use, copy, modify, merge, publish, 82 * distribute, and/or sell copies of the Software, and to permit persons 83 * to whom the Software is furnished to do so, provided that the above 84 * copyright notice(s) and this permission notice appear in all copies of 85 * the Software and that both the above copyright notice(s) and this 86 * permission notice appear in supporting documentation. 87 * 88 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 89 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 90 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 91 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 92 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 93 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 94 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 95 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 96 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 97 * 98 * Except as contained in this notice, the name of a copyright holder 99 * shall not be used in advertising or otherwise to promote the sale, use 100 * or other dealings in this Software without prior written authorization 101 * of the copyright holder. 102 */ 103 104/* Routines to manage various kinds of resources: 105 * 106 * CreateNewResourceType, CreateNewResourceClass, InitClientResources, 107 * FakeClientID, AddResource, FreeResource, FreeClientResources, 108 * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange 109 */ 110 111/* 112 * A resource ID is a 32 bit quantity, the upper 2 bits of which are 113 * off-limits for client-visible resources. The next 8 bits are 114 * used as client ID, and the low 22 bits come from the client. 115 * A resource ID is "hashed" by extracting and xoring subfields 116 * (varying with the size of the hash table). 117 * 118 * It is sometimes necessary for the server to create an ID that looks 119 * like it belongs to a client. This ID, however, must not be one 120 * the client actually can create, or we have the potential for conflict. 121 * The 31st bit of the ID is reserved for the server's use for this 122 * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to 123 * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a 124 * resource "owned" by the client. 125 */ 126 127#define NEED_EVENTS 128#ifdef HAVE_DIX_CONFIG_H 129#include <dix-config.h> 130#endif 131 132#include <X11/X.h> 133#include "misc.h" 134#include "os.h" 135#include "resource.h" 136#include "dixstruct.h" 137#include "opaque.h" 138#include "windowstr.h" 139#include "dixfont.h" 140#include "colormap.h" 141#include "inputstr.h" 142#include "dixevents.h" 143#include "dixgrabs.h" 144#include "cursor.h" 145#ifdef PANORAMIX 146#include "panoramiX.h" 147#include "panoramiXsrv.h" 148#endif 149#include "xace.h" 150#include <assert.h> 151 152#ifdef XSERVER_DTRACE 153#include <sys/types.h> 154typedef const char *string; 155#include "Xserver-dtrace.h" 156 157#define TypeNameString(t) NameForAtom(ResourceNames[t & TypeMask]) 158#endif 159 160static void RebuildTable( 161 int /*client*/ 162); 163 164#define SERVER_MINID 32 165 166#define INITBUCKETS 64 167#define INITHASHSIZE 6 168#define MAXHASHSIZE 11 169 170typedef struct _Resource { 171 struct _Resource *next; 172 XID id; 173 RESTYPE type; 174 pointer value; 175} ResourceRec, *ResourcePtr; 176#define NullResource ((ResourcePtr)NULL) 177 178typedef struct _ClientResource { 179 ResourcePtr *resources; 180 int elements; 181 int buckets; 182 int hashsize; /* log(2)(buckets) */ 183 XID fakeID; 184 XID endFakeID; 185 XID expectID; 186} ClientResourceRec; 187 188_X_EXPORT RESTYPE lastResourceType; 189static RESTYPE lastResourceClass; 190_X_EXPORT RESTYPE TypeMask; 191 192static DeleteType *DeleteFuncs = (DeleteType *)NULL; 193 194#ifdef XResExtension 195 196_X_EXPORT Atom * ResourceNames = NULL; 197 198_X_EXPORT void RegisterResourceName (RESTYPE type, char *name) 199{ 200 ResourceNames[type & TypeMask] = MakeAtom(name, strlen(name), TRUE); 201} 202 203#endif 204 205_X_EXPORT RESTYPE 206CreateNewResourceType(DeleteType deleteFunc) 207{ 208 RESTYPE next = lastResourceType + 1; 209 DeleteType *funcs; 210 211 if (next & lastResourceClass) 212 return 0; 213 funcs = (DeleteType *)xrealloc(DeleteFuncs, 214 (next + 1) * sizeof(DeleteType)); 215 if (!funcs) 216 return 0; 217 218#ifdef XResExtension 219 { 220 Atom *newnames; 221 newnames = xrealloc(ResourceNames, (next + 1) * sizeof(Atom)); 222 if(!newnames) 223 return 0; 224 ResourceNames = newnames; 225 ResourceNames[next] = 0; 226 } 227#endif 228 229 lastResourceType = next; 230 DeleteFuncs = funcs; 231 DeleteFuncs[next] = deleteFunc; 232 return next; 233} 234 235_X_EXPORT RESTYPE 236CreateNewResourceClass(void) 237{ 238 RESTYPE next = lastResourceClass >> 1; 239 240 if (next & lastResourceType) 241 return 0; 242 lastResourceClass = next; 243 TypeMask = next - 1; 244 return next; 245} 246 247static ClientResourceRec clientTable[MAXCLIENTS]; 248 249/***************** 250 * InitClientResources 251 * When a new client is created, call this to allocate space 252 * in resource table 253 *****************/ 254 255Bool 256InitClientResources(ClientPtr client) 257{ 258 int i, j; 259 260 if (client == serverClient) 261 { 262 lastResourceType = RT_LASTPREDEF; 263 lastResourceClass = RC_LASTPREDEF; 264 TypeMask = RC_LASTPREDEF - 1; 265 if (DeleteFuncs) 266 xfree(DeleteFuncs); 267 DeleteFuncs = (DeleteType *)xalloc((lastResourceType + 1) * 268 sizeof(DeleteType)); 269 if (!DeleteFuncs) 270 return FALSE; 271 DeleteFuncs[RT_NONE & TypeMask] = (DeleteType)NoopDDA; 272 DeleteFuncs[RT_WINDOW & TypeMask] = DeleteWindow; 273 DeleteFuncs[RT_PIXMAP & TypeMask] = dixDestroyPixmap; 274 DeleteFuncs[RT_GC & TypeMask] = FreeGC; 275 DeleteFuncs[RT_FONT & TypeMask] = CloseFont; 276 DeleteFuncs[RT_CURSOR & TypeMask] = FreeCursor; 277 DeleteFuncs[RT_COLORMAP & TypeMask] = FreeColormap; 278 DeleteFuncs[RT_CMAPENTRY & TypeMask] = FreeClientPixels; 279 DeleteFuncs[RT_OTHERCLIENT & TypeMask] = OtherClientGone; 280 DeleteFuncs[RT_PASSIVEGRAB & TypeMask] = DeletePassiveGrab; 281 282#ifdef XResExtension 283 if(ResourceNames) 284 xfree(ResourceNames); 285 ResourceNames = xalloc((lastResourceType + 1) * sizeof(Atom)); 286 if(!ResourceNames) 287 return FALSE; 288#endif 289 } 290 clientTable[i = client->index].resources = 291 (ResourcePtr *)xalloc(INITBUCKETS*sizeof(ResourcePtr)); 292 if (!clientTable[i].resources) 293 return FALSE; 294 clientTable[i].buckets = INITBUCKETS; 295 clientTable[i].elements = 0; 296 clientTable[i].hashsize = INITHASHSIZE; 297 /* Many IDs allocated from the server client are visible to clients, 298 * so we don't use the SERVER_BIT for them, but we have to start 299 * past the magic value constants used in the protocol. For normal 300 * clients, we can start from zero, with SERVER_BIT set. 301 */ 302 clientTable[i].fakeID = client->clientAsMask | 303 (client->index ? SERVER_BIT : SERVER_MINID); 304 clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; 305 clientTable[i].expectID = client->clientAsMask; 306 for (j=0; j<INITBUCKETS; j++) 307 { 308 clientTable[i].resources[j] = NullResource; 309 } 310 return TRUE; 311} 312 313 314static int 315Hash(int client, XID id) 316{ 317 id &= RESOURCE_ID_MASK; 318 switch (clientTable[client].hashsize) 319 { 320 case 6: 321 return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12)))); 322 case 7: 323 return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); 324 case 8: 325 return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); 326 case 9: 327 return ((int)(0x1FF & (id ^ (id>>9)))); 328 case 10: 329 return ((int)(0x3FF & (id ^ (id>>10)))); 330 case 11: 331 return ((int)(0x7FF & (id ^ (id>>11)))); 332 } 333 return -1; 334} 335 336static XID 337AvailableID( 338 int client, 339 XID id, 340 XID maxid, 341 XID goodid) 342{ 343 ResourcePtr res; 344 345 if ((goodid >= id) && (goodid <= maxid)) 346 return goodid; 347 for (; id <= maxid; id++) 348 { 349 res = clientTable[client].resources[Hash(client, id)]; 350 while (res && (res->id != id)) 351 res = res->next; 352 if (!res) 353 return id; 354 } 355 return 0; 356} 357 358_X_EXPORT void 359GetXIDRange(int client, Bool server, XID *minp, XID *maxp) 360{ 361 XID id, maxid; 362 ResourcePtr *resp; 363 ResourcePtr res; 364 int i; 365 XID goodid; 366 367 id = (Mask)client << CLIENTOFFSET; 368 if (server) 369 id |= client ? SERVER_BIT : SERVER_MINID; 370 maxid = id | RESOURCE_ID_MASK; 371 goodid = 0; 372 for (resp = clientTable[client].resources, i = clientTable[client].buckets; 373 --i >= 0;) 374 { 375 for (res = *resp++; res; res = res->next) 376 { 377 if ((res->id < id) || (res->id > maxid)) 378 continue; 379 if (((res->id - id) >= (maxid - res->id)) ? 380 (goodid = AvailableID(client, id, res->id - 1, goodid)) : 381 !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) 382 maxid = res->id - 1; 383 else 384 id = res->id + 1; 385 } 386 } 387 if (id > maxid) 388 id = maxid = 0; 389 *minp = id; 390 *maxp = maxid; 391} 392 393/** 394 * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. 395 * This function tries to find count unused XIDs for the given client. It 396 * puts the IDs in the array pids and returns the number found, which should 397 * almost always be the number requested. 398 * 399 * The circumstances that lead to a call to this function are very rare. 400 * Xlib must run out of IDs while trying to generate a request that wants 401 * multiple ID's, like the Multi-buffering CreateImageBuffers request. 402 * 403 * No rocket science in the implementation; just iterate over all 404 * possible IDs for the given client and pick the first count IDs 405 * that aren't in use. A more efficient algorithm could probably be 406 * invented, but this will be used so rarely that this should suffice. 407 */ 408 409_X_EXPORT unsigned int 410GetXIDList(ClientPtr pClient, unsigned count, XID *pids) 411{ 412 unsigned int found = 0; 413 XID id = pClient->clientAsMask; 414 XID maxid; 415 416 maxid = id | RESOURCE_ID_MASK; 417 while ( (found < count) && (id <= maxid) ) 418 { 419 if (!LookupIDByClass(id, RC_ANY)) 420 { 421 pids[found++] = id; 422 } 423 id++; 424 } 425 return found; 426} 427 428/* 429 * Return the next usable fake client ID. 430 * 431 * Normally this is just the next one in line, but if we've used the last 432 * in the range, we need to find a new range of safe IDs to avoid 433 * over-running another client. 434 */ 435 436_X_EXPORT XID 437FakeClientID(int client) 438{ 439 XID id, maxid; 440 441 id = clientTable[client].fakeID++; 442 if (id != clientTable[client].endFakeID) 443 return id; 444 GetXIDRange(client, TRUE, &id, &maxid); 445 if (!id) { 446 if (!client) 447 FatalError("FakeClientID: server internal ids exhausted\n"); 448 MarkClientException(clients[client]); 449 id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); 450 maxid = id | RESOURCE_ID_MASK; 451 } 452 clientTable[client].fakeID = id + 1; 453 clientTable[client].endFakeID = maxid + 1; 454 return id; 455} 456 457_X_EXPORT Bool 458AddResource(XID id, RESTYPE type, pointer value) 459{ 460 int client; 461 ClientResourceRec *rrec; 462 ResourcePtr res, *head; 463 464#ifdef XSERVER_DTRACE 465 XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); 466#endif 467 client = CLIENT_ID(id); 468 rrec = &clientTable[client]; 469 if (!rrec->buckets) 470 { 471 ErrorF("AddResource(%lx, %lx, %lx), client=%d \n", 472 (unsigned long)id, type, (unsigned long)value, client); 473 FatalError("client not in use\n"); 474 } 475 if ((rrec->elements >= 4*rrec->buckets) && 476 (rrec->hashsize < MAXHASHSIZE)) 477 RebuildTable(client); 478 head = &rrec->resources[Hash(client, id)]; 479 res = (ResourcePtr)xalloc(sizeof(ResourceRec)); 480 if (!res) 481 { 482 (*DeleteFuncs[type & TypeMask])(value, id); 483 return FALSE; 484 } 485 res->next = *head; 486 res->id = id; 487 res->type = type; 488 res->value = value; 489 *head = res; 490 rrec->elements++; 491 if (!(id & SERVER_BIT) && (id >= rrec->expectID)) 492 rrec->expectID = id + 1; 493 return TRUE; 494} 495 496static void 497RebuildTable(int client) 498{ 499 int j; 500 ResourcePtr res, next; 501 ResourcePtr **tails, *resources; 502 ResourcePtr **tptr, *rptr; 503 504 /* 505 * For now, preserve insertion order, since some ddx layers depend 506 * on resources being free in the opposite order they are added. 507 */ 508 509 j = 2 * clientTable[client].buckets; 510 tails = (ResourcePtr **)ALLOCATE_LOCAL(j * sizeof(ResourcePtr *)); 511 if (!tails) 512 return; 513 resources = (ResourcePtr *)xalloc(j * sizeof(ResourcePtr)); 514 if (!resources) 515 { 516 DEALLOCATE_LOCAL(tails); 517 return; 518 } 519 for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) 520 { 521 *rptr = NullResource; 522 *tptr = rptr; 523 } 524 clientTable[client].hashsize++; 525 for (j = clientTable[client].buckets, 526 rptr = clientTable[client].resources; 527 --j >= 0; 528 rptr++) 529 { 530 for (res = *rptr; res; res = next) 531 { 532 next = res->next; 533 res->next = NullResource; 534 tptr = &tails[Hash(client, res->id)]; 535 **tptr = res; 536 *tptr = &res->next; 537 } 538 } 539 DEALLOCATE_LOCAL(tails); 540 clientTable[client].buckets *= 2; 541 xfree(clientTable[client].resources); 542 clientTable[client].resources = resources; 543} 544 545_X_EXPORT void 546FreeResource(XID id, RESTYPE skipDeleteFuncType) 547{ 548 int cid; 549 ResourcePtr res; 550 ResourcePtr *prev, *head; 551 int *eltptr; 552 int elements; 553 Bool gotOne = FALSE; 554 555 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 556 { 557 head = &clientTable[cid].resources[Hash(cid, id)]; 558 eltptr = &clientTable[cid].elements; 559 560 prev = head; 561 while ( (res = *prev) ) 562 { 563 if (res->id == id) 564 { 565 RESTYPE rtype = res->type; 566 567#ifdef XSERVER_DTRACE 568 XSERVER_RESOURCE_FREE(res->id, res->type, 569 res->value, TypeNameString(res->type)); 570#endif 571 *prev = res->next; 572 elements = --*eltptr; 573 if (rtype & RC_CACHED) 574 FlushClientCaches(res->id); 575 if (rtype != skipDeleteFuncType) 576 (*DeleteFuncs[rtype & TypeMask])(res->value, res->id); 577 xfree(res); 578 if (*eltptr != elements) 579 prev = head; /* prev may no longer be valid */ 580 gotOne = TRUE; 581 } 582 else 583 prev = &res->next; 584 } 585 if(clients[cid] && (id == clients[cid]->lastDrawableID)) 586 { 587 clients[cid]->lastDrawable = (DrawablePtr)WindowTable[0]; 588 clients[cid]->lastDrawableID = WindowTable[0]->drawable.id; 589 } 590 } 591 if (!gotOne) 592 ErrorF("Freeing resource id=%lX which isn't there.\n", 593 (unsigned long)id); 594} 595 596 597_X_EXPORT void 598FreeResourceByType(XID id, RESTYPE type, Bool skipFree) 599{ 600 int cid; 601 ResourcePtr res; 602 ResourcePtr *prev, *head; 603 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 604 { 605 head = &clientTable[cid].resources[Hash(cid, id)]; 606 607 prev = head; 608 while ( (res = *prev) ) 609 { 610 if (res->id == id && res->type == type) 611 { 612#ifdef XSERVER_DTRACE 613 XSERVER_RESOURCE_FREE(res->id, res->type, 614 res->value, TypeNameString(res->type)); 615#endif 616 *prev = res->next; 617 if (type & RC_CACHED) 618 FlushClientCaches(res->id); 619 if (!skipFree) 620 (*DeleteFuncs[type & TypeMask])(res->value, res->id); 621 xfree(res); 622 break; 623 } 624 else 625 prev = &res->next; 626 } 627 if(clients[cid] && (id == clients[cid]->lastDrawableID)) 628 { 629 clients[cid]->lastDrawable = (DrawablePtr)WindowTable[0]; 630 clients[cid]->lastDrawableID = WindowTable[0]->drawable.id; 631 } 632 } 633} 634 635/* 636 * Change the value associated with a resource id. Caller 637 * is responsible for "doing the right thing" with the old 638 * data 639 */ 640 641_X_EXPORT Bool 642ChangeResourceValue (XID id, RESTYPE rtype, pointer value) 643{ 644 int cid; 645 ResourcePtr res; 646 647 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 648 { 649 res = clientTable[cid].resources[Hash(cid, id)]; 650 651 for (; res; res = res->next) 652 if ((res->id == id) && (res->type == rtype)) 653 { 654 if (rtype & RC_CACHED) 655 FlushClientCaches(res->id); 656 res->value = value; 657 return TRUE; 658 } 659 } 660 return FALSE; 661} 662 663/* Note: if func adds or deletes resources, then func can get called 664 * more than once for some resources. If func adds new resources, 665 * func might or might not get called for them. func cannot both 666 * add and delete an equal number of resources! 667 */ 668 669_X_EXPORT void 670FindClientResourcesByType( 671 ClientPtr client, 672 RESTYPE type, 673 FindResType func, 674 pointer cdata 675){ 676 ResourcePtr *resources; 677 ResourcePtr this, next; 678 int i, elements; 679 int *eltptr; 680 681 if (!client) 682 client = serverClient; 683 684 resources = clientTable[client->index].resources; 685 eltptr = &clientTable[client->index].elements; 686 for (i = 0; i < clientTable[client->index].buckets; i++) 687 { 688 for (this = resources[i]; this; this = next) 689 { 690 next = this->next; 691 if (!type || this->type == type) { 692 elements = *eltptr; 693 (*func)(this->value, this->id, cdata); 694 if (*eltptr != elements) 695 next = resources[i]; /* start over */ 696 } 697 } 698 } 699} 700 701_X_EXPORT void 702FindAllClientResources( 703 ClientPtr client, 704 FindAllRes func, 705 pointer cdata 706){ 707 ResourcePtr *resources; 708 ResourcePtr this, next; 709 int i, elements; 710 int *eltptr; 711 712 if (!client) 713 client = serverClient; 714 715 resources = clientTable[client->index].resources; 716 eltptr = &clientTable[client->index].elements; 717 for (i = 0; i < clientTable[client->index].buckets; i++) 718 { 719 for (this = resources[i]; this; this = next) 720 { 721 next = this->next; 722 elements = *eltptr; 723 (*func)(this->value, this->id, this->type, cdata); 724 if (*eltptr != elements) 725 next = resources[i]; /* start over */ 726 } 727 } 728} 729 730 731pointer 732LookupClientResourceComplex( 733 ClientPtr client, 734 RESTYPE type, 735 FindComplexResType func, 736 pointer cdata 737){ 738 ResourcePtr *resources; 739 ResourcePtr this; 740 int i; 741 742 if (!client) 743 client = serverClient; 744 745 resources = clientTable[client->index].resources; 746 for (i = 0; i < clientTable[client->index].buckets; i++) { 747 for (this = resources[i]; this; this = this->next) { 748 if (!type || this->type == type) { 749 if((*func)(this->value, this->id, cdata)) 750 return this->value; 751 } 752 } 753 } 754 return NULL; 755} 756 757 758void 759FreeClientNeverRetainResources(ClientPtr client) 760{ 761 ResourcePtr *resources; 762 ResourcePtr this; 763 ResourcePtr *prev; 764 int j; 765 766 if (!client) 767 return; 768 769 resources = clientTable[client->index].resources; 770 for (j=0; j < clientTable[client->index].buckets; j++) 771 { 772 prev = &resources[j]; 773 while ( (this = *prev) ) 774 { 775 RESTYPE rtype = this->type; 776 if (rtype & RC_NEVERRETAIN) 777 { 778#ifdef XSERVER_DTRACE 779 XSERVER_RESOURCE_FREE(this->id, this->type, 780 this->value, TypeNameString(this->type)); 781#endif 782 *prev = this->next; 783 if (rtype & RC_CACHED) 784 FlushClientCaches(this->id); 785 (*DeleteFuncs[rtype & TypeMask])(this->value, this->id); 786 xfree(this); 787 } 788 else 789 prev = &this->next; 790 } 791 } 792} 793 794void 795FreeClientResources(ClientPtr client) 796{ 797 ResourcePtr *resources; 798 ResourcePtr this; 799 int j; 800 801 /* This routine shouldn't be called with a null client, but just in 802 case ... */ 803 804 if (!client) 805 return; 806 807 HandleSaveSet(client); 808 809 resources = clientTable[client->index].resources; 810 for (j=0; j < clientTable[client->index].buckets; j++) 811 { 812 /* It may seem silly to update the head of this resource list as 813 we delete the members, since the entire list will be deleted any way, 814 but there are some resource deletion functions "FreeClientPixels" for 815 one which do a LookupID on another resource id (a Colormap id in this 816 case), so the resource list must be kept valid up to the point that 817 it is deleted, so every time we delete a resource, we must update the 818 head, just like in FreeResource. I hope that this doesn't slow down 819 mass deletion appreciably. PRH */ 820 821 ResourcePtr *head; 822 823 head = &resources[j]; 824 825 for (this = *head; this; this = *head) 826 { 827 RESTYPE rtype = this->type; 828#ifdef XSERVER_DTRACE 829 XSERVER_RESOURCE_FREE(this->id, this->type, 830 this->value, TypeNameString(this->type)); 831#endif 832 *head = this->next; 833 if (rtype & RC_CACHED) 834 FlushClientCaches(this->id); 835 (*DeleteFuncs[rtype & TypeMask])(this->value, this->id); 836 xfree(this); 837 } 838 } 839 xfree(clientTable[client->index].resources); 840 clientTable[client->index].resources = NULL; 841 clientTable[client->index].buckets = 0; 842} 843 844void 845FreeAllResources(void) 846{ 847 int i; 848 849 for (i = currentMaxClients; --i >= 0; ) 850 { 851 if (clientTable[i].buckets) 852 FreeClientResources(clients[i]); 853 } 854} 855 856_X_EXPORT Bool 857LegalNewID(XID id, ClientPtr client) 858{ 859 860#ifdef PANORAMIX 861 XID minid, maxid; 862 863 if (!noPanoramiXExtension) { 864 minid = client->clientAsMask | (client->index ? 865 SERVER_BIT : SERVER_MINID); 866 maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; 867 if ((id >= minid) && (id <= maxid)) 868 return TRUE; 869 } 870#endif /* PANORAMIX */ 871 return ((client->clientAsMask == (id & ~RESOURCE_ID_MASK)) && 872 ((clientTable[client->index].expectID <= id) || 873 !LookupIDByClass(id, RC_ANY))); 874} 875 876/* SecurityLookupIDByType and SecurityLookupIDByClass: 877 * These are the heart of the resource ID security system. They take 878 * two additional arguments compared to the old LookupID functions: 879 * the client doing the lookup, and the access mode (see resource.h). 880 * The resource is returned if it exists and the client is allowed access, 881 * else NULL is returned. 882 */ 883 884_X_EXPORT pointer 885SecurityLookupIDByType(ClientPtr client, XID id, RESTYPE rtype, Mask mode) 886{ 887 int cid; 888 ResourcePtr res; 889 pointer retval = NULL; 890 891 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && 892 clientTable[cid].buckets) 893 { 894 res = clientTable[cid].resources[Hash(cid, id)]; 895 896 for (; res; res = res->next) 897 if ((res->id == id) && (res->type == rtype)) 898 { 899 retval = res->value; 900 break; 901 } 902 } 903 if (retval && client && 904 !XaceHook(XACE_RESOURCE_ACCESS, client, id, rtype, mode, retval)) 905 retval = NULL; 906 907 return retval; 908} 909 910 911_X_EXPORT pointer 912SecurityLookupIDByClass(ClientPtr client, XID id, RESTYPE classes, Mask mode) 913{ 914 int cid; 915 ResourcePtr res = NULL; 916 pointer retval = NULL; 917 918 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && 919 clientTable[cid].buckets) 920 { 921 res = clientTable[cid].resources[Hash(cid, id)]; 922 923 for (; res; res = res->next) 924 if ((res->id == id) && (res->type & classes)) 925 { 926 retval = res->value; 927 break; 928 } 929 } 930 if (retval && client && 931 !XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, mode, retval)) 932 retval = NULL; 933 934 return retval; 935} 936 937/* We can't replace the LookupIDByType and LookupIDByClass functions with 938 * macros because of compatibility with loadable servers. 939 */ 940 941_X_EXPORT pointer 942LookupIDByType(XID id, RESTYPE rtype) 943{ 944 return SecurityLookupIDByType(NullClient, id, rtype, 945 DixUnknownAccess); 946} 947 948_X_EXPORT pointer 949LookupIDByClass(XID id, RESTYPE classes) 950{ 951 return SecurityLookupIDByClass(NullClient, id, classes, 952 DixUnknownAccess); 953} 954