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