Imported Upstream version 1.15.1
[deb_xorg-server.git] / Xext / xres.c
CommitLineData
a09e091a
JB
1/*
2 Copyright (c) 2002 XFree86 Inc
3*/
4
5#ifdef HAVE_DIX_CONFIG_H
6#include <dix-config.h>
7#endif
8
9#include <stdio.h>
10#include <string.h>
11#include <X11/X.h>
12#include <X11/Xproto.h>
13#include <assert.h>
14#include "misc.h"
15#include "os.h"
16#include "dixstruct.h"
17#include "extnsionst.h"
18#include "swaprep.h"
19#include "registry.h"
20#include <X11/extensions/XResproto.h>
21#include "pixmapstr.h"
22#include "windowstr.h"
23#include "gcstruct.h"
24#include "extinit.h"
25#include "protocol-versions.h"
26#include "client.h"
27#include "list.h"
28#include "misc.h"
29#include <string.h>
30#include "hashtable.h"
31#include "picturestr.h"
32
33#ifdef COMPOSITE
34#include "compint.h"
35#endif
36
37/** @brief Holds fragments of responses for ConstructClientIds.
38 *
39 * note: there is no consideration for data alignment */
40typedef struct {
41 struct xorg_list l;
42 int bytes;
43 /* data follows */
44} FragmentList;
45
46#define FRAGMENT_DATA(ptr) ((void*) ((char*) (ptr) + sizeof(FragmentList)))
47
48/** @brief Holds structure for the generated response to
49 ProcXResQueryClientIds; used by ConstructClientId* -functions */
50typedef struct {
51 int numIds;
52 int resultBytes;
53 struct xorg_list response;
54 int sentClientMasks[MAXCLIENTS];
55} ConstructClientIdCtx;
56
57/** @brief Holds the structure for information required to
58 generate the response to XResQueryResourceBytes. In addition
59 to response it contains information on the query as well,
60 as well as some volatile information required by a few
61 functions that cannot take that information directly
62 via a parameter, as they are called via already-existing
63 higher order functions. */
64typedef struct {
65 ClientPtr sendClient;
66 int numSizes;
67 int resultBytes;
68 struct xorg_list response;
69 int status;
70 long numSpecs;
71 xXResResourceIdSpec *specs;
72 HashTable visitedResources;
73
74 /* Used by AddSubResourceSizeSpec when AddResourceSizeValue is
75 handling crossreferences */
76 HashTable visitedSubResources;
77
78 /* used when ConstructResourceBytesCtx is passed to
79 AddResourceSizeValue2 via FindClientResourcesByType */
80 RESTYPE resType;
81
82 /* used when ConstructResourceBytesCtx is passed to
83 AddResourceSizeValueByResource from ConstructResourceBytesByResource */
84 xXResResourceIdSpec *curSpec;
85
86 /** Used when iterating through a single resource's subresources
87
88 @see AddSubResourceSizeSpec */
89 xXResResourceSizeValue *sizeValue;
90} ConstructResourceBytesCtx;
91
92/** @brief Allocate and add a sequence of bytes at the end of a fragment list.
93 Call DestroyFragments to release the list.
94
95 @param frags A pointer to head of an initialized linked list
96 @param bytes Number of bytes to allocate
97 @return Returns a pointer to the allocated non-zeroed region
98 that is to be filled by the caller. On error (out of memory)
99 returns NULL and makes no changes to the list.
100*/
101static void *
102AddFragment(struct xorg_list *frags, int bytes)
103{
104 FragmentList *f = malloc(sizeof(FragmentList) + bytes);
105 if (!f) {
106 return NULL;
107 } else {
108 f->bytes = bytes;
109 xorg_list_add(&f->l, frags->prev);
110 return (char*) f + sizeof(*f);
111 }
112}
113
114/** @brief Sends all fragments in the list to the client. Does not
115 free anything.
116
117 @param client The client to send the fragments to
118 @param frags The head of the list of fragments
119*/
120static void
121WriteFragmentsToClient(ClientPtr client, struct xorg_list *frags)
122{
123 FragmentList *it;
124 xorg_list_for_each_entry(it, frags, l) {
125 WriteToClient(client, it->bytes, (char*) it + sizeof(*it));
126 }
127}
128
129/** @brief Frees a list of fragments. Does not free() root node.
130
131 @param frags The head of the list of fragments
132*/
133static void
134DestroyFragments(struct xorg_list *frags)
135{
136 FragmentList *it, *tmp;
137 xorg_list_for_each_entry_safe(it, tmp, frags, l) {
138 xorg_list_del(&it->l);
139 free(it);
140 }
141}
142
143/** @brief Constructs a context record for ConstructClientId* functions
144 to use */
145static void
146InitConstructClientIdCtx(ConstructClientIdCtx *ctx)
147{
148 ctx->numIds = 0;
149 ctx->resultBytes = 0;
150 xorg_list_init(&ctx->response);
151 memset(ctx->sentClientMasks, 0, sizeof(ctx->sentClientMasks));
152}
153
154/** @brief Destroys a context record, releases all memory (except the storage
155 for *ctx itself) */
156static void
157DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
158{
159 DestroyFragments(&ctx->response);
160}
161
162static Bool
163InitConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx,
164 ClientPtr sendClient,
165 long numSpecs,
166 xXResResourceIdSpec *specs)
167{
168 ctx->sendClient = sendClient;
169 ctx->numSizes = 0;
170 ctx->resultBytes = 0;
171 xorg_list_init(&ctx->response);
172 ctx->status = Success;
173 ctx->numSpecs = numSpecs;
174 ctx->specs = specs;
175 ctx->visitedResources = ht_create(sizeof(XID), 0,
176 ht_resourceid_hash, ht_resourceid_compare,
177 NULL);
178
179 if (!ctx->visitedResources) {
180 return FALSE;
181 } else {
182 return TRUE;
183 }
184}
185
186static void
187DestroyConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx)
188{
189 DestroyFragments(&ctx->response);
190 ht_destroy(ctx->visitedResources);
191}
192
193static int
194ProcXResQueryVersion(ClientPtr client)
195{
196 REQUEST(xXResQueryVersionReq);
197 xXResQueryVersionReply rep = {
198 .type = X_Reply,
199 .sequenceNumber = client->sequence,
200 .length = 0,
201 .server_major = SERVER_XRES_MAJOR_VERSION,
202 .server_minor = SERVER_XRES_MINOR_VERSION
203 };
204
205 REQUEST_SIZE_MATCH(xXResQueryVersionReq);
206
207 if (client->swapped) {
208 swaps(&rep.sequenceNumber);
209 swapl(&rep.length);
210 swaps(&rep.server_major);
211 swaps(&rep.server_minor);
212 }
213 WriteToClient(client, sizeof(xXResQueryVersionReply), &rep);
214 return Success;
215}
216
217static int
218ProcXResQueryClients(ClientPtr client)
219{
220 /* REQUEST(xXResQueryClientsReq); */
221 xXResQueryClientsReply rep;
222 int *current_clients;
223 int i, num_clients;
224
225 REQUEST_SIZE_MATCH(xXResQueryClientsReq);
226
227 current_clients = malloc(currentMaxClients * sizeof(int));
228
229 num_clients = 0;
230 for (i = 0; i < currentMaxClients; i++) {
231 if (clients[i]) {
232 current_clients[num_clients] = i;
233 num_clients++;
234 }
235 }
236
237 rep = (xXResQueryClientsReply) {
238 .type = X_Reply,
239 .sequenceNumber = client->sequence,
240 .length = bytes_to_int32(num_clients * sz_xXResClient),
241 .num_clients = num_clients
242 };
243 if (client->swapped) {
244 swaps(&rep.sequenceNumber);
245 swapl(&rep.length);
246 swapl(&rep.num_clients);
247 }
248 WriteToClient(client, sizeof(xXResQueryClientsReply), &rep);
249
250 if (num_clients) {
251 xXResClient scratch;
252
253 for (i = 0; i < num_clients; i++) {
254 scratch.resource_base = clients[current_clients[i]]->clientAsMask;
255 scratch.resource_mask = RESOURCE_ID_MASK;
256
257 if (client->swapped) {
258 swapl(&scratch.resource_base);
259 swapl(&scratch.resource_mask);
260 }
261 WriteToClient(client, sz_xXResClient, &scratch);
262 }
263 }
264
265 free(current_clients);
266
267 return Success;
268}
269
270static void
271ResFindAllRes(pointer value, XID id, RESTYPE type, pointer cdata)
272{
273 int *counts = (int *) cdata;
274
275 counts[(type & TypeMask) - 1]++;
276}
277
278static int
279ProcXResQueryClientResources(ClientPtr client)
280{
281 REQUEST(xXResQueryClientResourcesReq);
282 xXResQueryClientResourcesReply rep;
283 int i, clientID, num_types;
284 int *counts;
285
286 REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
287
288 clientID = CLIENT_ID(stuff->xid);
289
290 if ((clientID >= currentMaxClients) || !clients[clientID]) {
291 client->errorValue = stuff->xid;
292 return BadValue;
293 }
294
295 counts = calloc(lastResourceType + 1, sizeof(int));
296
297 FindAllClientResources(clients[clientID], ResFindAllRes, counts);
298
299 num_types = 0;
300
301 for (i = 0; i <= lastResourceType; i++) {
302 if (counts[i])
303 num_types++;
304 }
305
306 rep = (xXResQueryClientResourcesReply) {
307 .type = X_Reply,
308 .sequenceNumber = client->sequence,
309 .length = bytes_to_int32(num_types * sz_xXResType),
310 .num_types = num_types
311 };
312 if (client->swapped) {
313 swaps(&rep.sequenceNumber);
314 swapl(&rep.length);
315 swapl(&rep.num_types);
316 }
317
318 WriteToClient(client, sizeof(xXResQueryClientResourcesReply), &rep);
319
320 if (num_types) {
321 xXResType scratch;
322 const char *name;
323
324 for (i = 0; i < lastResourceType; i++) {
325 if (!counts[i])
326 continue;
327
328 name = LookupResourceName(i + 1);
329 if (strcmp(name, XREGISTRY_UNKNOWN))
330 scratch.resource_type = MakeAtom(name, strlen(name), TRUE);
331 else {
332 char buf[40];
333
334 snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1);
335 scratch.resource_type = MakeAtom(buf, strlen(buf), TRUE);
336 }
337
338 scratch.count = counts[i];
339
340 if (client->swapped) {
341 swapl(&scratch.resource_type);
342 swapl(&scratch.count);
343 }
344 WriteToClient(client, sz_xXResType, &scratch);
345 }
346 }
347
348 free(counts);
349
350 return Success;
351}
352
353static unsigned long
354ResGetApproxPixmapBytes(PixmapPtr pix)
355{
356 unsigned long nPixels;
357 int bytesPerPixel;
358
359 bytesPerPixel = pix->drawable.bitsPerPixel >> 3;
360 nPixels = pix->drawable.width * pix->drawable.height;
361
362 /* Divide by refcnt as pixmap could be shared between clients,
363 * so total pixmap mem is shared between these.
364 */
365 return (nPixels * bytesPerPixel) / pix->refcnt;
366}
367
368static void
369ResFindResourcePixmaps(pointer value, XID id, RESTYPE type, pointer cdata)
370{
371 SizeType sizeFunc = GetResourceTypeSizeFunc(type);
372 ResourceSizeRec size = { 0, 0, 0 };
373 unsigned long *bytes = cdata;
374
375 sizeFunc(value, id, &size);
376 *bytes += size.pixmapRefSize;
377}
378
379static void
380ResFindPixmaps(pointer value, XID id, pointer cdata)
381{
382 unsigned long *bytes = (unsigned long *) cdata;
383 PixmapPtr pix = (PixmapPtr) value;
384
385 *bytes += ResGetApproxPixmapBytes(pix);
386}
387
388static void
389ResFindWindowPixmaps(pointer value, XID id, pointer cdata)
390{
391 unsigned long *bytes = (unsigned long *) cdata;
392 WindowPtr pWin = (WindowPtr) value;
393
394 if (pWin->backgroundState == BackgroundPixmap)
395 *bytes += ResGetApproxPixmapBytes(pWin->background.pixmap);
396
397 if (pWin->border.pixmap != NULL && !pWin->borderIsPixel)
398 *bytes += ResGetApproxPixmapBytes(pWin->border.pixmap);
399}
400
401static void
402ResFindGCPixmaps(pointer value, XID id, pointer cdata)
403{
404 unsigned long *bytes = (unsigned long *) cdata;
405 GCPtr pGC = (GCPtr) value;
406
407 if (pGC->stipple != NULL)
408 *bytes += ResGetApproxPixmapBytes(pGC->stipple);
409
410 if (pGC->tile.pixmap != NULL && !pGC->tileIsPixel)
411 *bytes += ResGetApproxPixmapBytes(pGC->tile.pixmap);
412}
413
414static void
415ResFindPicturePixmaps(pointer value, XID id, pointer cdata)
416{
417#ifdef RENDER
418 ResFindResourcePixmaps(value, id, PictureType, cdata);
419#endif
420}
421
422static void
423ResFindCompositeClientWindowPixmaps (pointer value, XID id, pointer cdata)
424{
425#ifdef COMPOSITE
426 ResFindResourcePixmaps(value, id, CompositeClientWindowType, cdata);
427#endif
428}
429
430static int
431ProcXResQueryClientPixmapBytes(ClientPtr client)
432{
433 REQUEST(xXResQueryClientPixmapBytesReq);
434 xXResQueryClientPixmapBytesReply rep;
435 int clientID;
436 unsigned long bytes;
437
438 REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
439
440 clientID = CLIENT_ID(stuff->xid);
441
442 if ((clientID >= currentMaxClients) || !clients[clientID]) {
443 client->errorValue = stuff->xid;
444 return BadValue;
445 }
446
447 bytes = 0;
448
449 FindClientResourcesByType(clients[clientID], RT_PIXMAP, ResFindPixmaps,
450 (pointer) (&bytes));
451
452 /*
453 * Make sure win background pixmaps also held to account.
454 */
455 FindClientResourcesByType(clients[clientID], RT_WINDOW,
456 ResFindWindowPixmaps, (pointer) (&bytes));
457
458 /*
459 * GC Tile & Stipple pixmaps too.
460 */
461 FindClientResourcesByType(clients[clientID], RT_GC,
462 ResFindGCPixmaps, (pointer) (&bytes));
463
464#ifdef RENDER
465 /* Render extension picture pixmaps. */
466 FindClientResourcesByType(clients[clientID], PictureType,
467 ResFindPicturePixmaps,
468 (pointer)(&bytes));
469#endif
470
471#ifdef COMPOSITE
472 /* Composite extension client window pixmaps. */
473 FindClientResourcesByType(clients[clientID], CompositeClientWindowType,
474 ResFindCompositeClientWindowPixmaps,
475 (pointer)(&bytes));
476#endif
477
478 rep = (xXResQueryClientPixmapBytesReply) {
479 .type = X_Reply,
480 .sequenceNumber = client->sequence,
481 .length = 0,
482 .bytes = bytes,
483#ifdef _XSERVER64
484 .bytes_overflow = bytes >> 32
485#else
486 .bytes_overflow = 0
487#endif
488 };
489 if (client->swapped) {
490 swaps(&rep.sequenceNumber);
491 swapl(&rep.length);
492 swapl(&rep.bytes);
493 swapl(&rep.bytes_overflow);
494 }
495 WriteToClient(client, sizeof(xXResQueryClientPixmapBytesReply), &rep);
496
497 return Success;
498}
499
500/** @brief Finds out if a client's information need to be put into the
501 response; marks client having been handled, if that is the case.
502
503 @param client The client to send information about
504 @param mask The request mask (0 to send everything, otherwise a
505 bitmask of X_XRes*Mask)
506 @param ctx The context record that tells which clients and id types
507 have been already handled
508 @param sendMask Which id type are we now considering. One of X_XRes*Mask.
509
510 @return Returns TRUE if the client information needs to be on the
511 response, otherwise FALSE.
512*/
513static Bool
514WillConstructMask(ClientPtr client, CARD32 mask,
515 ConstructClientIdCtx *ctx, int sendMask)
516{
517 if ((!mask || (mask & sendMask))
518 && !(ctx->sentClientMasks[client->index] & sendMask)) {
519 ctx->sentClientMasks[client->index] |= sendMask;
520 return TRUE;
521 } else {
522 return FALSE;
523 }
524}
525
526/** @brief Constructs a response about a single client, based on a certain
527 client id spec
528
529 @param sendClient Which client wishes to receive this answer. Used for
530 byte endianess.
531 @param client Which client are we considering.
532 @param mask The client id spec mask indicating which information
533 we want about this client.
534 @param ctx The context record containing the constructed response
535 and information on which clients and masks have been
536 already handled.
537
538 @return Return TRUE if everything went OK, otherwise FALSE which indicates
539 a memory allocation problem.
540*/
541static Bool
542ConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask,
543 ConstructClientIdCtx *ctx)
544{
545 xXResClientIdValue rep;
546
547 rep.spec.client = client->clientAsMask;
548 if (client->swapped) {
549 swapl (&rep.spec.client);
550 }
551
552 if (WillConstructMask(client, mask, ctx, X_XResClientXIDMask)) {
553 void *ptr = AddFragment(&ctx->response, sizeof(rep));
554 if (!ptr) {
555 return FALSE;
556 }
557
558 rep.spec.mask = X_XResClientXIDMask;
559 rep.length = 0;
560 if (sendClient->swapped) {
561 swapl (&rep.spec.mask);
562 /* swapl (&rep.length, n); - not required for rep.length = 0 */
563 }
564
565 memcpy(ptr, &rep, sizeof(rep));
566
567 ctx->resultBytes += sizeof(rep);
568 ++ctx->numIds;
569 }
570 if (WillConstructMask(client, mask, ctx, X_XResLocalClientPIDMask)) {
571 pid_t pid = GetClientPid(client);
572
573 if (pid != -1) {
574 void *ptr = AddFragment(&ctx->response,
575 sizeof(rep) + sizeof(CARD32));
576 CARD32 *value = (void*) ((char*) ptr + sizeof(rep));
577
578 if (!ptr) {
579 return FALSE;
580 }
581
582 rep.spec.mask = X_XResLocalClientPIDMask;
583 rep.length = 4;
584
585 if (sendClient->swapped) {
586 swapl (&rep.spec.mask);
587 swapl (&rep.length);
588 }
589
590 if (sendClient->swapped) {
591 swapl (value);
592 }
593 memcpy(ptr, &rep, sizeof(rep));
594 *value = pid;
595
596 ctx->resultBytes += sizeof(rep) + sizeof(CARD32);
597 ++ctx->numIds;
598 }
599 }
600
601 /* memory allocation errors earlier may return with FALSE */
602 return TRUE;
603}
604
605/** @brief Constructs a response about all clients, based on a client id specs
606
607 @param client Which client which we are constructing the response for.
608 @param numSpecs Number of client id specs in specs
609 @param specs Client id specs
610
611 @return Return Success if everything went OK, otherwise a Bad* (currently
612 BadAlloc or BadValue)
613*/
614static int
615ConstructClientIds(ClientPtr client,
616 int numSpecs, xXResClientIdSpec* specs,
617 ConstructClientIdCtx *ctx)
618{
619 int specIdx;
620
621 for (specIdx = 0; specIdx < numSpecs; ++specIdx) {
622 if (specs[specIdx].client == 0) {
623 int c;
624 for (c = 0; c < currentMaxClients; ++c) {
625 if (clients[c]) {
626 if (!ConstructClientIdValue(client, clients[c],
627 specs[specIdx].mask, ctx)) {
628 return BadAlloc;
629 }
630 }
631 }
632 } else {
633 int clientID = CLIENT_ID(specs[specIdx].client);
634
635 if ((clientID < currentMaxClients) && clients[clientID]) {
636 if (!ConstructClientIdValue(client, clients[clientID],
637 specs[specIdx].mask, ctx)) {
638 return BadAlloc;
639 }
640 }
641 }
642 }
643
644 /* memory allocation errors earlier may return with BadAlloc */
645 return Success;
646}
647
648/** @brief Response to XResQueryClientIds request introduced in XResProto v1.2
649
650 @param client Which client which we are constructing the response for.
651
652 @return Returns the value returned from ConstructClientIds with the same
653 semantics
654*/
655static int
656ProcXResQueryClientIds (ClientPtr client)
657{
658 REQUEST(xXResQueryClientIdsReq);
659
660 xXResClientIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
661 int rc;
662 ConstructClientIdCtx ctx;
663
664 InitConstructClientIdCtx(&ctx);
665
666 REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq);
667 REQUEST_FIXED_SIZE(xXResQueryClientIdsReq,
668 stuff->numSpecs * sizeof(specs[0]));
669
670 rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
671
672 if (rc == Success) {
673 xXResQueryClientIdsReply rep = {
674 .type = X_Reply,
675 .sequenceNumber = client->sequence,
676 .length = bytes_to_int32(ctx.resultBytes),
677 .numIds = ctx.numIds
678 };
679
680 assert((ctx.resultBytes & 3) == 0);
681
682 if (client->swapped) {
683 swaps (&rep.sequenceNumber);
684 swapl (&rep.length);
685 swapl (&rep.numIds);
686 }
687
688 WriteToClient(client, sizeof(rep), &rep);
689 WriteFragmentsToClient(client, &ctx.response);
690 }
691
692 DestroyConstructClientIdCtx(&ctx);
693
694 return rc;
695}
696
697/** @brief Swaps xXResResourceIdSpec endianess */
698static void
699SwapXResResourceIdSpec(xXResResourceIdSpec *spec)
700{
701 swapl(&spec->resource);
702 swapl(&spec->type);
703}
704
705/** @brief Swaps xXResResourceSizeSpec endianess */
706static void
707SwapXResResourceSizeSpec(xXResResourceSizeSpec *size)
708{
709 SwapXResResourceIdSpec(&size->spec);
710 swapl(&size->bytes);
711 swapl(&size->refCount);
712 swapl(&size->useCount);
713}
714
715/** @brief Swaps xXResResourceSizeValue endianess */
716static void
717SwapXResResourceSizeValue(xXResResourceSizeValue *rep)
718{
719 SwapXResResourceSizeSpec(&rep->size);
720 swapl(&rep->numCrossReferences);
721}
722
723/** @brief Swaps the response bytes */
724static void
725SwapXResQueryResourceBytes(struct xorg_list *response)
726{
727 struct xorg_list *it = response->next;
728 int c;
729
730 while (it != response) {
731 xXResResourceSizeValue *value = FRAGMENT_DATA(it);
732 it = it->next;
733 for (c = 0; c < value->numCrossReferences; ++c) {
734 xXResResourceSizeSpec *spec = FRAGMENT_DATA(it);
735 SwapXResResourceSizeSpec(spec);
736 it = it->next;
737 }
738 SwapXResResourceSizeValue(value);
739 }
740}
741
742/** @brief Adds xXResResourceSizeSpec describing a resource's size into
743 the buffer contained in the context. The resource is considered
744 to be a subresource.
745
746 @see AddResourceSizeValue
747
748 @param[in] value The X resource object on which to add information
749 about to the buffer
750 @param[in] id The ID of the X resource
751 @param[in] type The type of the X resource
752 @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
753 Void pointer type is used here to satisfy the type
754 FindRes
755*/
756static void
757AddSubResourceSizeSpec(pointer value,
758 XID id,
759 RESTYPE type,
760 pointer cdata)
761{
762 ConstructResourceBytesCtx *ctx = cdata;
763
764 if (ctx->status == Success) {
765 xXResResourceSizeSpec **prevCrossRef =
766 ht_find(ctx->visitedSubResources, &value);
767 if (!prevCrossRef) {
768 Bool ok = TRUE;
769 xXResResourceSizeSpec *crossRef =
770 AddFragment(&ctx->response, sizeof(xXResResourceSizeSpec));
771 ok = ok && crossRef != NULL;
772 if (ok) {
773 xXResResourceSizeSpec **p;
774 p = ht_add(ctx->visitedSubResources, &value);
775 if (!p) {
776 ok = FALSE;
777 } else {
778 *p = crossRef;
779 }
780 }
781 if (!ok) {
782 ctx->status = BadAlloc;
783 } else {
784 SizeType sizeFunc = GetResourceTypeSizeFunc(type);
785 ResourceSizeRec size = { 0, 0, 0 };
786 sizeFunc(value, id, &size);
787
788 crossRef->spec.resource = id;
789 crossRef->spec.type = type;
790 crossRef->bytes = size.resourceSize;
791 crossRef->refCount = size.refCnt;
792 crossRef->useCount = 1;
793
794 ++ctx->sizeValue->numCrossReferences;
795
796 ctx->resultBytes += sizeof(*crossRef);
797 }
798 } else {
799 /* if we have visited the subresource earlier (from current parent
800 resource), just increase its use count by one */
801 ++(*prevCrossRef)->useCount;
802 }
803 }
804}
805
806/** @brief Adds xXResResourceSizeValue describing a resource's size into
807 the buffer contained in the context. In addition, the
808 subresources are iterated and added as xXResResourceSizeSpec's
809 by using AddSubResourceSizeSpec
810
811 @see AddSubResourceSizeSpec
812
813 @param[in] value The X resource object on which to add information
814 about to the buffer
815 @param[in] id The ID of the X resource
816 @param[in] type The type of the X resource
817 @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
818 Void pointer type is used here to satisfy the type
819 FindRes
820*/
821static void
822AddResourceSizeValue(pointer ptr, XID id, RESTYPE type, pointer cdata)
823{
824 ConstructResourceBytesCtx *ctx = cdata;
825 if (ctx->status == Success &&
826 !ht_find(ctx->visitedResources, &id)) {
827 Bool ok = TRUE;
828 HashTable ht;
829 HtGenericHashSetupRec htSetup = {
830 .keySize = sizeof(void*)
831 };
832
833 /* it doesn't matter that we don't undo the work done here
834 * immediately. All but ht_init will be undone at the end
835 * of the request and there can happen no failure after
836 * ht_init, so we don't need to clean it up here in any
837 * special way */
838
839 xXResResourceSizeValue *value =
840 AddFragment(&ctx->response, sizeof(xXResResourceSizeValue));
841 if (!value) {
842 ok = FALSE;
843 }
844 ok = ok && ht_add(ctx->visitedResources, &id);
845 if (ok) {
846 ht = ht_create(htSetup.keySize,
847 sizeof(xXResResourceSizeSpec*),
848 ht_generic_hash, ht_generic_compare,
849 &htSetup);
850 ok = ok && ht;
851 }
852
853 if (!ok) {
854 ctx->status = BadAlloc;
855 } else {
856 SizeType sizeFunc = GetResourceTypeSizeFunc(type);
857 ResourceSizeRec size = { 0, 0, 0 };
858
859 sizeFunc(ptr, id, &size);
860
861 value->size.spec.resource = id;
862 value->size.spec.type = type;
863 value->size.bytes = size.resourceSize;
864 value->size.refCount = size.refCnt;
865 value->size.useCount = 1;
866 value->numCrossReferences = 0;
867
868 ctx->sizeValue = value;
869 ctx->visitedSubResources = ht;
870 FindSubResources(ptr, type, AddSubResourceSizeSpec, ctx);
871 ctx->visitedSubResources = NULL;
872 ctx->sizeValue = NULL;
873
874 ctx->resultBytes += sizeof(*value);
875 ++ctx->numSizes;
876
877 ht_destroy(ht);
878 }
879 }
880}
881
882/** @brief A variant of AddResourceSizeValue that passes the resource type
883 through the context object to satisfy the type FindResType
884
885 @see AddResourceSizeValue
886
887 @param[in] ptr The resource
888 @param[in] id The resource ID
889 @param[in/out] cdata The context object that contains the resource type
890*/
891static void
892AddResourceSizeValueWithResType(pointer ptr, XID id, pointer cdata)
893{
894 ConstructResourceBytesCtx *ctx = cdata;
895 AddResourceSizeValue(ptr, id, ctx->resType, cdata);
896}
897
898/** @brief Adds the information of a resource into the buffer if it matches
899 the match condition.
900
901 @see AddResourceSizeValue
902
903 @param[in] ptr The resource
904 @param[in] id The resource ID
905 @param[in] type The resource type
906 @param[in/out] cdata The context object as a void pointer to satisfy the
907 type FindAllRes
908*/
909static void
910AddResourceSizeValueByResource(pointer ptr, XID id, RESTYPE type, pointer cdata)
911{
912 ConstructResourceBytesCtx *ctx = cdata;
913 xXResResourceIdSpec *spec = ctx->curSpec;
914
915 if ((!spec->type || spec->type == type) &&
916 (!spec->resource || spec->resource == id)) {
917 AddResourceSizeValue(ptr, id, type, ctx);
918 }
919}
920
921/** @brief Add all resources of the client into the result buffer
922 disregarding all those specifications that specify the
923 resource by its ID. Those are handled by
924 ConstructResourceBytesByResource
925
926 @see ConstructResourceBytesByResource
927
928 @param[in] aboutClient Which client is being considered
929 @param[in/out] ctx The context that contains the resource id
930 specifications as well as the result buffer
931*/
932static void
933ConstructClientResourceBytes(ClientPtr aboutClient,
934 ConstructResourceBytesCtx *ctx)
935{
936 int specIdx;
937 for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
938 xXResResourceIdSpec* spec = ctx->specs + specIdx;
939 if (spec->resource) {
940 /* these specs are handled elsewhere */
941 } else if (spec->type) {
942 ctx->resType = spec->type;
943 FindClientResourcesByType(aboutClient, spec->type,
944 AddResourceSizeValueWithResType, ctx);
945 } else {
946 FindAllClientResources(aboutClient, AddResourceSizeValue, ctx);
947 }
948 }
949}
950
951/** @brief Add the sizes of all such resources that can are specified by
952 their ID in the resource id specification. The scan can
953 by limited to a client with the aboutClient parameter
954
955 @see ConstructResourceBytesByResource
956
957 @param[in] aboutClient Which client is being considered. This may be None
958 to mean all clients.
959 @param[in/out] ctx The context that contains the resource id
960 specifications as well as the result buffer. In
961 addition this function uses the curSpec field to
962 keep a pointer to the current resource id
963 specification in it, which can be used by
964 AddResourceSizeValueByResource .
965*/
966static void
967ConstructResourceBytesByResource(XID aboutClient, ConstructResourceBytesCtx *ctx)
968{
969 int specIdx;
970 for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
971 xXResResourceIdSpec *spec = ctx->specs + specIdx;
972 if (spec->resource) {
973 int cid = CLIENT_ID(spec->resource);
974 if (cid < currentMaxClients &&
975 (aboutClient == None || cid == aboutClient)) {
976 ClientPtr client = clients[cid];
977 if (client) {
978 ctx->curSpec = spec;
979 FindAllClientResources(client,
980 AddResourceSizeValueByResource,
981 ctx);
982 }
983 }
984 }
985 }
986}
987
988/** @brief Build the resource size response for the given client
989 (or all if not specified) per the parameters set up
990 in the context object.
991
992 @param[in] aboutClient Which client to consider or None for all clients
993 @param[in/out] ctx The context object that contains the request as well
994 as the response buffer.
995*/
996static int
997ConstructResourceBytes(XID aboutClient,
998 ConstructResourceBytesCtx *ctx)
999{
1000 if (aboutClient) {
1001 int clientIdx = CLIENT_ID(aboutClient);
1002 ClientPtr client = NullClient;
1003
1004 if ((clientIdx >= currentMaxClients) || !clients[clientIdx]) {
1005 ctx->sendClient->errorValue = aboutClient;
1006 return BadValue;
1007 }
1008
1009 client = clients[clientIdx];
1010
1011 ConstructClientResourceBytes(client, ctx);
1012 ConstructResourceBytesByResource(aboutClient, ctx);
1013 } else {
1014 int clientIdx;
1015
1016 ConstructClientResourceBytes(NULL, ctx);
1017
1018 for (clientIdx = 0; clientIdx < currentMaxClients; ++clientIdx) {
1019 ClientPtr client = clients[clientIdx];
1020
1021 if (client) {
1022 ConstructClientResourceBytes(client, ctx);
1023 }
1024 }
1025
1026 ConstructResourceBytesByResource(None, ctx);
1027 }
1028
1029
1030 return ctx->status;
1031}
1032
1033/** @brief Implements the XResQueryResourceBytes of XResProto v1.2 */
1034static int
1035ProcXResQueryResourceBytes (ClientPtr client)
1036{
1037 REQUEST(xXResQueryResourceBytesReq);
1038
1039 int rc;
1040 ConstructResourceBytesCtx ctx;
1041
1042 REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
1043 REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
1044 stuff->numSpecs * sizeof(ctx.specs[0]));
1045
1046 if (!InitConstructResourceBytesCtx(&ctx, client,
1047 stuff->numSpecs,
1048 (void*) ((char*) stuff +
1049 sz_xXResQueryResourceBytesReq))) {
1050 return BadAlloc;
1051 }
1052
1053 rc = ConstructResourceBytes(stuff->client, &ctx);
1054
1055 if (rc == Success) {
1056 xXResQueryResourceBytesReply rep = {
1057 .type = X_Reply,
1058 .sequenceNumber = client->sequence,
1059 .length = bytes_to_int32(ctx.resultBytes),
1060 .numSizes = ctx.numSizes
1061 };
1062
1063 if (client->swapped) {
1064 swaps (&rep.sequenceNumber);
1065 swapl (&rep.length);
1066 swapl (&rep.numSizes);
1067
1068 SwapXResQueryResourceBytes(&ctx.response);
1069 }
1070
1071 WriteToClient(client, sizeof(rep), &rep);
1072 WriteFragmentsToClient(client, &ctx.response);
1073 }
1074
1075 DestroyConstructResourceBytesCtx(&ctx);
1076
1077 return rc;
1078}
1079
1080static int
1081ProcResDispatch(ClientPtr client)
1082{
1083 REQUEST(xReq);
1084 switch (stuff->data) {
1085 case X_XResQueryVersion:
1086 return ProcXResQueryVersion(client);
1087 case X_XResQueryClients:
1088 return ProcXResQueryClients(client);
1089 case X_XResQueryClientResources:
1090 return ProcXResQueryClientResources(client);
1091 case X_XResQueryClientPixmapBytes:
1092 return ProcXResQueryClientPixmapBytes(client);
1093 case X_XResQueryClientIds:
1094 return ProcXResQueryClientIds(client);
1095 case X_XResQueryResourceBytes:
1096 return ProcXResQueryResourceBytes(client);
1097 default: break;
1098 }
1099
1100 return BadRequest;
1101}
1102
1103static int
1104SProcXResQueryVersion(ClientPtr client)
1105{
1106 REQUEST(xXResQueryVersionReq);
1107 REQUEST_SIZE_MATCH(xXResQueryVersionReq);
1108 return ProcXResQueryVersion(client);
1109}
1110
1111static int
1112SProcXResQueryClientResources(ClientPtr client)
1113{
1114 REQUEST(xXResQueryClientResourcesReq);
1115 REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
1116 swapl(&stuff->xid);
1117 return ProcXResQueryClientResources(client);
1118}
1119
1120static int
1121SProcXResQueryClientPixmapBytes(ClientPtr client)
1122{
1123 REQUEST(xXResQueryClientPixmapBytesReq);
1124 REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
1125 swapl(&stuff->xid);
1126 return ProcXResQueryClientPixmapBytes(client);
1127}
1128
1129static int
1130SProcXResQueryClientIds (ClientPtr client)
1131{
1132 REQUEST(xXResQueryClientIdsReq);
1133
1134 REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
1135 swapl(&stuff->numSpecs);
1136 return ProcXResQueryClientIds(client);
1137}
1138
1139/** @brief Implements the XResQueryResourceBytes of XResProto v1.2.
1140 This variant byteswaps request contents before issuing the
1141 rest of the work to ProcXResQueryResourceBytes */
1142static int
1143SProcXResQueryResourceBytes (ClientPtr client)
1144{
1145 REQUEST(xXResQueryResourceBytesReq);
1146 int c;
1147 xXResResourceIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
1148
1149 swapl(&stuff->numSpecs);
1150 REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
1151 REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
1152 stuff->numSpecs * sizeof(specs[0]));
1153
1154 for (c = 0; c < stuff->numSpecs; ++c) {
1155 SwapXResResourceIdSpec(specs + c);
1156 }
1157
1158 return ProcXResQueryResourceBytes(client);
1159}
1160
1161static int
1162SProcResDispatch (ClientPtr client)
1163{
1164 REQUEST(xReq);
1165 swaps(&stuff->length);
1166
1167 switch (stuff->data) {
1168 case X_XResQueryVersion:
1169 return SProcXResQueryVersion(client);
1170 case X_XResQueryClients: /* nothing to swap */
1171 return ProcXResQueryClients(client);
1172 case X_XResQueryClientResources:
1173 return SProcXResQueryClientResources(client);
1174 case X_XResQueryClientPixmapBytes:
1175 return SProcXResQueryClientPixmapBytes(client);
1176 case X_XResQueryClientIds:
1177 return SProcXResQueryClientIds(client);
1178 case X_XResQueryResourceBytes:
1179 return SProcXResQueryResourceBytes(client);
1180 default: break;
1181 }
1182
1183 return BadRequest;
1184}
1185
1186void
1187ResExtensionInit(void)
1188{
1189 (void) AddExtension(XRES_NAME, 0, 0,
1190 ProcResDispatch, SProcResDispatch,
1191 NULL, StandardMinorOpcode);
1192}