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 */
40 typedef 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 */
50 typedef 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. */
64 typedef 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 cross-references */
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 */
101 static void *
AddFragment(struct xorg_list * frags,int bytes)102 AddFragment(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 */
120 static void
WriteFragmentsToClient(ClientPtr client,struct xorg_list * frags)121 WriteFragmentsToClient(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 */
133 static void
DestroyFragments(struct xorg_list * frags)134 DestroyFragments(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 */
145 static void
InitConstructClientIdCtx(ConstructClientIdCtx * ctx)146 InitConstructClientIdCtx(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) */
156 static void
DestroyConstructClientIdCtx(ConstructClientIdCtx * ctx)157 DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
158 {
159 DestroyFragments(&ctx->response);
160 }
161
162 static Bool
InitConstructResourceBytesCtx(ConstructResourceBytesCtx * ctx,ClientPtr sendClient,long numSpecs,xXResResourceIdSpec * specs)163 InitConstructResourceBytesCtx(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
186 static void
DestroyConstructResourceBytesCtx(ConstructResourceBytesCtx * ctx)187 DestroyConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx)
188 {
189 DestroyFragments(&ctx->response);
190 ht_destroy(ctx->visitedResources);
191 }
192
193 static int
ProcXResQueryVersion(ClientPtr client)194 ProcXResQueryVersion(ClientPtr client)
195 {
196 xXResQueryVersionReply rep = {
197 .type = X_Reply,
198 .sequenceNumber = client->sequence,
199 .length = 0,
200 .server_major = SERVER_XRES_MAJOR_VERSION,
201 .server_minor = SERVER_XRES_MINOR_VERSION
202 };
203
204 REQUEST_SIZE_MATCH(xXResQueryVersionReq);
205
206 if (client->swapped) {
207 swaps(&rep.sequenceNumber);
208 swapl(&rep.length);
209 swaps(&rep.server_major);
210 swaps(&rep.server_minor);
211 }
212 WriteToClient(client, sizeof(xXResQueryVersionReply), &rep);
213 return Success;
214 }
215
216 static int
ProcXResQueryClients(ClientPtr client)217 ProcXResQueryClients(ClientPtr client)
218 {
219 /* REQUEST(xXResQueryClientsReq); */
220 xXResQueryClientsReply rep;
221 int *current_clients;
222 int i, num_clients;
223
224 REQUEST_SIZE_MATCH(xXResQueryClientsReq);
225
226 current_clients = xallocarray(currentMaxClients, sizeof(int));
227
228 num_clients = 0;
229 for (i = 0; i < currentMaxClients; i++) {
230 if (clients[i]) {
231 current_clients[num_clients] = i;
232 num_clients++;
233 }
234 }
235
236 rep = (xXResQueryClientsReply) {
237 .type = X_Reply,
238 .sequenceNumber = client->sequence,
239 .length = bytes_to_int32(num_clients * sz_xXResClient),
240 .num_clients = num_clients
241 };
242 if (client->swapped) {
243 swaps(&rep.sequenceNumber);
244 swapl(&rep.length);
245 swapl(&rep.num_clients);
246 }
247 WriteToClient(client, sizeof(xXResQueryClientsReply), &rep);
248
249 if (num_clients) {
250 xXResClient scratch;
251
252 for (i = 0; i < num_clients; i++) {
253 scratch.resource_base = clients[current_clients[i]]->clientAsMask;
254 scratch.resource_mask = RESOURCE_ID_MASK;
255
256 if (client->swapped) {
257 swapl(&scratch.resource_base);
258 swapl(&scratch.resource_mask);
259 }
260 WriteToClient(client, sz_xXResClient, &scratch);
261 }
262 }
263
264 free(current_clients);
265
266 return Success;
267 }
268
269 static void
ResFindAllRes(void * value,XID id,RESTYPE type,void * cdata)270 ResFindAllRes(void *value, XID id, RESTYPE type, void *cdata)
271 {
272 int *counts = (int *) cdata;
273
274 counts[(type & TypeMask) - 1]++;
275 }
276
277 static CARD32
resourceTypeAtom(int i)278 resourceTypeAtom(int i)
279 {
280 CARD32 ret;
281
282 const char *name = LookupResourceName(i);
283 if (strcmp(name, XREGISTRY_UNKNOWN))
284 ret = MakeAtom(name, strlen(name), TRUE);
285 else {
286 char buf[40];
287
288 snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1);
289 ret = MakeAtom(buf, strlen(buf), TRUE);
290 }
291
292 return ret;
293 }
294
295 static int
ProcXResQueryClientResources(ClientPtr client)296 ProcXResQueryClientResources(ClientPtr client)
297 {
298 REQUEST(xXResQueryClientResourcesReq);
299 xXResQueryClientResourcesReply rep;
300 int i, clientID, num_types;
301 int *counts;
302
303 REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
304
305 clientID = CLIENT_ID(stuff->xid);
306
307 if ((clientID >= currentMaxClients) || !clients[clientID]) {
308 client->errorValue = stuff->xid;
309 return BadValue;
310 }
311
312 counts = calloc(lastResourceType + 1, sizeof(int));
313
314 FindAllClientResources(clients[clientID], ResFindAllRes, counts);
315
316 num_types = 0;
317
318 for (i = 0; i <= lastResourceType; i++) {
319 if (counts[i])
320 num_types++;
321 }
322
323 rep = (xXResQueryClientResourcesReply) {
324 .type = X_Reply,
325 .sequenceNumber = client->sequence,
326 .length = bytes_to_int32(num_types * sz_xXResType),
327 .num_types = num_types
328 };
329 if (client->swapped) {
330 swaps(&rep.sequenceNumber);
331 swapl(&rep.length);
332 swapl(&rep.num_types);
333 }
334
335 WriteToClient(client, sizeof(xXResQueryClientResourcesReply), &rep);
336
337 if (num_types) {
338 xXResType scratch;
339
340 for (i = 0; i < lastResourceType; i++) {
341 if (!counts[i])
342 continue;
343
344 scratch.resource_type = resourceTypeAtom(i + 1);
345 scratch.count = counts[i];
346
347 if (client->swapped) {
348 swapl(&scratch.resource_type);
349 swapl(&scratch.count);
350 }
351 WriteToClient(client, sz_xXResType, &scratch);
352 }
353 }
354
355 free(counts);
356
357 return Success;
358 }
359
360 static void
ResFindResourcePixmaps(void * value,XID id,RESTYPE type,void * cdata)361 ResFindResourcePixmaps(void *value, XID id, RESTYPE type, void *cdata)
362 {
363 SizeType sizeFunc = GetResourceTypeSizeFunc(type);
364 ResourceSizeRec size = { 0, 0, 0 };
365 unsigned long *bytes = cdata;
366
367 sizeFunc(value, id, &size);
368 *bytes += size.pixmapRefSize;
369 }
370
371 static int
ProcXResQueryClientPixmapBytes(ClientPtr client)372 ProcXResQueryClientPixmapBytes(ClientPtr client)
373 {
374 REQUEST(xXResQueryClientPixmapBytesReq);
375 xXResQueryClientPixmapBytesReply rep;
376 int clientID;
377 unsigned long bytes;
378
379 REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
380
381 clientID = CLIENT_ID(stuff->xid);
382
383 if ((clientID >= currentMaxClients) || !clients[clientID]) {
384 client->errorValue = stuff->xid;
385 return BadValue;
386 }
387
388 bytes = 0;
389
390 FindAllClientResources(clients[clientID], ResFindResourcePixmaps,
391 (void *) (&bytes));
392
393 rep = (xXResQueryClientPixmapBytesReply) {
394 .type = X_Reply,
395 .sequenceNumber = client->sequence,
396 .length = 0,
397 .bytes = bytes,
398 #ifdef _XSERVER64
399 .bytes_overflow = bytes >> 32
400 #else
401 .bytes_overflow = 0
402 #endif
403 };
404 if (client->swapped) {
405 swaps(&rep.sequenceNumber);
406 swapl(&rep.length);
407 swapl(&rep.bytes);
408 swapl(&rep.bytes_overflow);
409 }
410 WriteToClient(client, sizeof(xXResQueryClientPixmapBytesReply), &rep);
411
412 return Success;
413 }
414
415 /** @brief Finds out if a client's information need to be put into the
416 response; marks client having been handled, if that is the case.
417
418 @param client The client to send information about
419 @param mask The request mask (0 to send everything, otherwise a
420 bitmask of X_XRes*Mask)
421 @param ctx The context record that tells which clients and id types
422 have been already handled
423 @param sendMask Which id type are we now considering. One of X_XRes*Mask.
424
425 @return Returns TRUE if the client information needs to be on the
426 response, otherwise FALSE.
427 */
428 static Bool
WillConstructMask(ClientPtr client,CARD32 mask,ConstructClientIdCtx * ctx,int sendMask)429 WillConstructMask(ClientPtr client, CARD32 mask,
430 ConstructClientIdCtx *ctx, int sendMask)
431 {
432 if ((!mask || (mask & sendMask))
433 && !(ctx->sentClientMasks[client->index] & sendMask)) {
434 ctx->sentClientMasks[client->index] |= sendMask;
435 return TRUE;
436 } else {
437 return FALSE;
438 }
439 }
440
441 /** @brief Constructs a response about a single client, based on a certain
442 client id spec
443
444 @param sendClient Which client wishes to receive this answer. Used for
445 byte endianness.
446 @param client Which client are we considering.
447 @param mask The client id spec mask indicating which information
448 we want about this client.
449 @param ctx The context record containing the constructed response
450 and information on which clients and masks have been
451 already handled.
452
453 @return Return TRUE if everything went OK, otherwise FALSE which indicates
454 a memory allocation problem.
455 */
456 static Bool
ConstructClientIdValue(ClientPtr sendClient,ClientPtr client,CARD32 mask,ConstructClientIdCtx * ctx)457 ConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask,
458 ConstructClientIdCtx *ctx)
459 {
460 xXResClientIdValue rep;
461
462 rep.spec.client = client->clientAsMask;
463 if (client->swapped) {
464 swapl (&rep.spec.client);
465 }
466
467 if (WillConstructMask(client, mask, ctx, X_XResClientXIDMask)) {
468 void *ptr = AddFragment(&ctx->response, sizeof(rep));
469 if (!ptr) {
470 return FALSE;
471 }
472
473 rep.spec.mask = X_XResClientXIDMask;
474 rep.length = 0;
475 if (sendClient->swapped) {
476 swapl (&rep.spec.mask);
477 /* swapl (&rep.length, n); - not required for rep.length = 0 */
478 }
479
480 memcpy(ptr, &rep, sizeof(rep));
481
482 ctx->resultBytes += sizeof(rep);
483 ++ctx->numIds;
484 }
485 if (WillConstructMask(client, mask, ctx, X_XResLocalClientPIDMask)) {
486 pid_t pid = GetClientPid(client);
487
488 if (pid != -1) {
489 void *ptr = AddFragment(&ctx->response,
490 sizeof(rep) + sizeof(CARD32));
491 CARD32 *value = (void*) ((char*) ptr + sizeof(rep));
492
493 if (!ptr) {
494 return FALSE;
495 }
496
497 rep.spec.mask = X_XResLocalClientPIDMask;
498 rep.length = 4;
499
500 if (sendClient->swapped) {
501 swapl (&rep.spec.mask);
502 swapl (&rep.length);
503 }
504
505 if (sendClient->swapped) {
506 swapl (value);
507 }
508 memcpy(ptr, &rep, sizeof(rep));
509 *value = pid;
510
511 ctx->resultBytes += sizeof(rep) + sizeof(CARD32);
512 ++ctx->numIds;
513 }
514 }
515
516 /* memory allocation errors earlier may return with FALSE */
517 return TRUE;
518 }
519
520 /** @brief Constructs a response about all clients, based on a client id specs
521
522 @param client Which client which we are constructing the response for.
523 @param numSpecs Number of client id specs in specs
524 @param specs Client id specs
525
526 @return Return Success if everything went OK, otherwise a Bad* (currently
527 BadAlloc or BadValue)
528 */
529 static int
ConstructClientIds(ClientPtr client,int numSpecs,xXResClientIdSpec * specs,ConstructClientIdCtx * ctx)530 ConstructClientIds(ClientPtr client,
531 int numSpecs, xXResClientIdSpec* specs,
532 ConstructClientIdCtx *ctx)
533 {
534 int specIdx;
535
536 for (specIdx = 0; specIdx < numSpecs; ++specIdx) {
537 if (specs[specIdx].client == 0) {
538 int c;
539 for (c = 0; c < currentMaxClients; ++c) {
540 if (clients[c]) {
541 if (!ConstructClientIdValue(client, clients[c],
542 specs[specIdx].mask, ctx)) {
543 return BadAlloc;
544 }
545 }
546 }
547 } else {
548 int clientID = CLIENT_ID(specs[specIdx].client);
549
550 if ((clientID < currentMaxClients) && clients[clientID]) {
551 if (!ConstructClientIdValue(client, clients[clientID],
552 specs[specIdx].mask, ctx)) {
553 return BadAlloc;
554 }
555 }
556 }
557 }
558
559 /* memory allocation errors earlier may return with BadAlloc */
560 return Success;
561 }
562
563 /** @brief Response to XResQueryClientIds request introduced in XResProto v1.2
564
565 @param client Which client which we are constructing the response for.
566
567 @return Returns the value returned from ConstructClientIds with the same
568 semantics
569 */
570 static int
ProcXResQueryClientIds(ClientPtr client)571 ProcXResQueryClientIds (ClientPtr client)
572 {
573 REQUEST(xXResQueryClientIdsReq);
574
575 xXResClientIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
576 int rc;
577 ConstructClientIdCtx ctx;
578
579 InitConstructClientIdCtx(&ctx);
580
581 REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq);
582 REQUEST_FIXED_SIZE(xXResQueryClientIdsReq,
583 stuff->numSpecs * sizeof(specs[0]));
584
585 rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
586
587 if (rc == Success) {
588 xXResQueryClientIdsReply rep = {
589 .type = X_Reply,
590 .sequenceNumber = client->sequence,
591 .length = bytes_to_int32(ctx.resultBytes),
592 .numIds = ctx.numIds
593 };
594
595 assert((ctx.resultBytes & 3) == 0);
596
597 if (client->swapped) {
598 swaps (&rep.sequenceNumber);
599 swapl (&rep.length);
600 swapl (&rep.numIds);
601 }
602
603 WriteToClient(client, sizeof(rep), &rep);
604 WriteFragmentsToClient(client, &ctx.response);
605 }
606
607 DestroyConstructClientIdCtx(&ctx);
608
609 return rc;
610 }
611
612 /** @brief Swaps xXResResourceIdSpec endianness */
613 static void
SwapXResResourceIdSpec(xXResResourceIdSpec * spec)614 SwapXResResourceIdSpec(xXResResourceIdSpec *spec)
615 {
616 swapl(&spec->resource);
617 swapl(&spec->type);
618 }
619
620 /** @brief Swaps xXResResourceSizeSpec endianness */
621 static void
SwapXResResourceSizeSpec(xXResResourceSizeSpec * size)622 SwapXResResourceSizeSpec(xXResResourceSizeSpec *size)
623 {
624 SwapXResResourceIdSpec(&size->spec);
625 swapl(&size->bytes);
626 swapl(&size->refCount);
627 swapl(&size->useCount);
628 }
629
630 /** @brief Swaps xXResResourceSizeValue endianness */
631 static void
SwapXResResourceSizeValue(xXResResourceSizeValue * rep)632 SwapXResResourceSizeValue(xXResResourceSizeValue *rep)
633 {
634 SwapXResResourceSizeSpec(&rep->size);
635 swapl(&rep->numCrossReferences);
636 }
637
638 /** @brief Swaps the response bytes */
639 static void
SwapXResQueryResourceBytes(struct xorg_list * response)640 SwapXResQueryResourceBytes(struct xorg_list *response)
641 {
642 struct xorg_list *it = response->next;
643 int c;
644
645 while (it != response) {
646 xXResResourceSizeValue *value = FRAGMENT_DATA(it);
647 it = it->next;
648 for (c = 0; c < value->numCrossReferences; ++c) {
649 xXResResourceSizeSpec *spec = FRAGMENT_DATA(it);
650 SwapXResResourceSizeSpec(spec);
651 it = it->next;
652 }
653 SwapXResResourceSizeValue(value);
654 }
655 }
656
657 /** @brief Adds xXResResourceSizeSpec describing a resource's size into
658 the buffer contained in the context. The resource is considered
659 to be a subresource.
660
661 @see AddResourceSizeValue
662
663 @param[in] value The X resource object on which to add information
664 about to the buffer
665 @param[in] id The ID of the X resource
666 @param[in] type The type of the X resource
667 @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
668 Void pointer type is used here to satisfy the type
669 FindRes
670 */
671 static void
AddSubResourceSizeSpec(void * value,XID id,RESTYPE type,void * cdata)672 AddSubResourceSizeSpec(void *value,
673 XID id,
674 RESTYPE type,
675 void *cdata)
676 {
677 ConstructResourceBytesCtx *ctx = cdata;
678
679 if (ctx->status == Success) {
680 xXResResourceSizeSpec **prevCrossRef =
681 ht_find(ctx->visitedSubResources, &value);
682 if (!prevCrossRef) {
683 Bool ok = TRUE;
684 xXResResourceSizeSpec *crossRef =
685 AddFragment(&ctx->response, sizeof(xXResResourceSizeSpec));
686 ok = ok && crossRef != NULL;
687 if (ok) {
688 xXResResourceSizeSpec **p;
689 p = ht_add(ctx->visitedSubResources, &value);
690 if (!p) {
691 ok = FALSE;
692 } else {
693 *p = crossRef;
694 }
695 }
696 if (!ok) {
697 ctx->status = BadAlloc;
698 } else {
699 SizeType sizeFunc = GetResourceTypeSizeFunc(type);
700 ResourceSizeRec size = { 0, 0, 0 };
701 sizeFunc(value, id, &size);
702
703 crossRef->spec.resource = id;
704 crossRef->spec.type = resourceTypeAtom(type);
705 crossRef->bytes = size.resourceSize;
706 crossRef->refCount = size.refCnt;
707 crossRef->useCount = 1;
708
709 ++ctx->sizeValue->numCrossReferences;
710
711 ctx->resultBytes += sizeof(*crossRef);
712 }
713 } else {
714 /* if we have visited the subresource earlier (from current parent
715 resource), just increase its use count by one */
716 ++(*prevCrossRef)->useCount;
717 }
718 }
719 }
720
721 /** @brief Adds xXResResourceSizeValue describing a resource's size into
722 the buffer contained in the context. In addition, the
723 subresources are iterated and added as xXResResourceSizeSpec's
724 by using AddSubResourceSizeSpec
725
726 @see AddSubResourceSizeSpec
727
728 @param[in] value The X resource object on which to add information
729 about to the buffer
730 @param[in] id The ID of the X resource
731 @param[in] type The type of the X resource
732 @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
733 Void pointer type is used here to satisfy the type
734 FindRes
735 */
736 static void
AddResourceSizeValue(void * ptr,XID id,RESTYPE type,void * cdata)737 AddResourceSizeValue(void *ptr, XID id, RESTYPE type, void *cdata)
738 {
739 ConstructResourceBytesCtx *ctx = cdata;
740 if (ctx->status == Success &&
741 !ht_find(ctx->visitedResources, &id)) {
742 Bool ok = TRUE;
743 HashTable ht;
744 HtGenericHashSetupRec htSetup = {
745 .keySize = sizeof(void*)
746 };
747
748 /* it doesn't matter that we don't undo the work done here
749 * immediately. All but ht_init will be undone at the end
750 * of the request and there can happen no failure after
751 * ht_init, so we don't need to clean it up here in any
752 * special way */
753
754 xXResResourceSizeValue *value =
755 AddFragment(&ctx->response, sizeof(xXResResourceSizeValue));
756 if (!value) {
757 ok = FALSE;
758 }
759 ok = ok && ht_add(ctx->visitedResources, &id);
760 if (ok) {
761 ht = ht_create(htSetup.keySize,
762 sizeof(xXResResourceSizeSpec*),
763 ht_generic_hash, ht_generic_compare,
764 &htSetup);
765 ok = ok && ht;
766 }
767
768 if (!ok) {
769 ctx->status = BadAlloc;
770 } else {
771 SizeType sizeFunc = GetResourceTypeSizeFunc(type);
772 ResourceSizeRec size = { 0, 0, 0 };
773
774 sizeFunc(ptr, id, &size);
775
776 value->size.spec.resource = id;
777 value->size.spec.type = resourceTypeAtom(type);
778 value->size.bytes = size.resourceSize;
779 value->size.refCount = size.refCnt;
780 value->size.useCount = 1;
781 value->numCrossReferences = 0;
782
783 ctx->sizeValue = value;
784 ctx->visitedSubResources = ht;
785 FindSubResources(ptr, type, AddSubResourceSizeSpec, ctx);
786 ctx->visitedSubResources = NULL;
787 ctx->sizeValue = NULL;
788
789 ctx->resultBytes += sizeof(*value);
790 ++ctx->numSizes;
791
792 ht_destroy(ht);
793 }
794 }
795 }
796
797 /** @brief A variant of AddResourceSizeValue that passes the resource type
798 through the context object to satisfy the type FindResType
799
800 @see AddResourceSizeValue
801
802 @param[in] ptr The resource
803 @param[in] id The resource ID
804 @param[in/out] cdata The context object that contains the resource type
805 */
806 static void
AddResourceSizeValueWithResType(void * ptr,XID id,void * cdata)807 AddResourceSizeValueWithResType(void *ptr, XID id, void *cdata)
808 {
809 ConstructResourceBytesCtx *ctx = cdata;
810 AddResourceSizeValue(ptr, id, ctx->resType, cdata);
811 }
812
813 /** @brief Adds the information of a resource into the buffer if it matches
814 the match condition.
815
816 @see AddResourceSizeValue
817
818 @param[in] ptr The resource
819 @param[in] id The resource ID
820 @param[in] type The resource type
821 @param[in/out] cdata The context object as a void pointer to satisfy the
822 type FindAllRes
823 */
824 static void
AddResourceSizeValueByResource(void * ptr,XID id,RESTYPE type,void * cdata)825 AddResourceSizeValueByResource(void *ptr, XID id, RESTYPE type, void *cdata)
826 {
827 ConstructResourceBytesCtx *ctx = cdata;
828 xXResResourceIdSpec *spec = ctx->curSpec;
829
830 if ((!spec->type || spec->type == type) &&
831 (!spec->resource || spec->resource == id)) {
832 AddResourceSizeValue(ptr, id, type, ctx);
833 }
834 }
835
836 /** @brief Add all resources of the client into the result buffer
837 disregarding all those specifications that specify the
838 resource by its ID. Those are handled by
839 ConstructResourceBytesByResource
840
841 @see ConstructResourceBytesByResource
842
843 @param[in] aboutClient Which client is being considered
844 @param[in/out] ctx The context that contains the resource id
845 specifications as well as the result buffer
846 */
847 static void
ConstructClientResourceBytes(ClientPtr aboutClient,ConstructResourceBytesCtx * ctx)848 ConstructClientResourceBytes(ClientPtr aboutClient,
849 ConstructResourceBytesCtx *ctx)
850 {
851 int specIdx;
852 for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
853 xXResResourceIdSpec* spec = ctx->specs + specIdx;
854 if (spec->resource) {
855 /* these specs are handled elsewhere */
856 } else if (spec->type) {
857 ctx->resType = spec->type;
858 FindClientResourcesByType(aboutClient, spec->type,
859 AddResourceSizeValueWithResType, ctx);
860 } else {
861 FindAllClientResources(aboutClient, AddResourceSizeValue, ctx);
862 }
863 }
864 }
865
866 /** @brief Add the sizes of all such resources that can are specified by
867 their ID in the resource id specification. The scan can
868 by limited to a client with the aboutClient parameter
869
870 @see ConstructResourceBytesByResource
871
872 @param[in] aboutClient Which client is being considered. This may be None
873 to mean all clients.
874 @param[in/out] ctx The context that contains the resource id
875 specifications as well as the result buffer. In
876 addition this function uses the curSpec field to
877 keep a pointer to the current resource id
878 specification in it, which can be used by
879 AddResourceSizeValueByResource .
880 */
881 static void
ConstructResourceBytesByResource(XID aboutClient,ConstructResourceBytesCtx * ctx)882 ConstructResourceBytesByResource(XID aboutClient, ConstructResourceBytesCtx *ctx)
883 {
884 int specIdx;
885 for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
886 xXResResourceIdSpec *spec = ctx->specs + specIdx;
887 if (spec->resource) {
888 int cid = CLIENT_ID(spec->resource);
889 if (cid < currentMaxClients &&
890 (aboutClient == None || cid == aboutClient)) {
891 ClientPtr client = clients[cid];
892 if (client) {
893 ctx->curSpec = spec;
894 FindAllClientResources(client,
895 AddResourceSizeValueByResource,
896 ctx);
897 }
898 }
899 }
900 }
901 }
902
903 /** @brief Build the resource size response for the given client
904 (or all if not specified) per the parameters set up
905 in the context object.
906
907 @param[in] aboutClient Which client to consider or None for all clients
908 @param[in/out] ctx The context object that contains the request as well
909 as the response buffer.
910 */
911 static int
ConstructResourceBytes(XID aboutClient,ConstructResourceBytesCtx * ctx)912 ConstructResourceBytes(XID aboutClient,
913 ConstructResourceBytesCtx *ctx)
914 {
915 if (aboutClient) {
916 int clientIdx = CLIENT_ID(aboutClient);
917 ClientPtr client = NullClient;
918
919 if ((clientIdx >= currentMaxClients) || !clients[clientIdx]) {
920 ctx->sendClient->errorValue = aboutClient;
921 return BadValue;
922 }
923
924 client = clients[clientIdx];
925
926 ConstructClientResourceBytes(client, ctx);
927 ConstructResourceBytesByResource(aboutClient, ctx);
928 } else {
929 int clientIdx;
930
931 ConstructClientResourceBytes(NULL, ctx);
932
933 for (clientIdx = 0; clientIdx < currentMaxClients; ++clientIdx) {
934 ClientPtr client = clients[clientIdx];
935
936 if (client) {
937 ConstructClientResourceBytes(client, ctx);
938 }
939 }
940
941 ConstructResourceBytesByResource(None, ctx);
942 }
943
944
945 return ctx->status;
946 }
947
948 /** @brief Implements the XResQueryResourceBytes of XResProto v1.2 */
949 static int
ProcXResQueryResourceBytes(ClientPtr client)950 ProcXResQueryResourceBytes (ClientPtr client)
951 {
952 REQUEST(xXResQueryResourceBytesReq);
953
954 int rc;
955 ConstructResourceBytesCtx ctx;
956
957 REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
958 if (stuff->numSpecs > UINT32_MAX / sizeof(ctx.specs[0]))
959 return BadLength;
960 REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
961 stuff->numSpecs * sizeof(ctx.specs[0]));
962
963 if (!InitConstructResourceBytesCtx(&ctx, client,
964 stuff->numSpecs,
965 (void*) ((char*) stuff +
966 sz_xXResQueryResourceBytesReq))) {
967 return BadAlloc;
968 }
969
970 rc = ConstructResourceBytes(stuff->client, &ctx);
971
972 if (rc == Success) {
973 xXResQueryResourceBytesReply rep = {
974 .type = X_Reply,
975 .sequenceNumber = client->sequence,
976 .length = bytes_to_int32(ctx.resultBytes),
977 .numSizes = ctx.numSizes
978 };
979
980 if (client->swapped) {
981 swaps (&rep.sequenceNumber);
982 swapl (&rep.length);
983 swapl (&rep.numSizes);
984
985 SwapXResQueryResourceBytes(&ctx.response);
986 }
987
988 WriteToClient(client, sizeof(rep), &rep);
989 WriteFragmentsToClient(client, &ctx.response);
990 }
991
992 DestroyConstructResourceBytesCtx(&ctx);
993
994 return rc;
995 }
996
997 static int
ProcResDispatch(ClientPtr client)998 ProcResDispatch(ClientPtr client)
999 {
1000 REQUEST(xReq);
1001 switch (stuff->data) {
1002 case X_XResQueryVersion:
1003 return ProcXResQueryVersion(client);
1004 case X_XResQueryClients:
1005 return ProcXResQueryClients(client);
1006 case X_XResQueryClientResources:
1007 return ProcXResQueryClientResources(client);
1008 case X_XResQueryClientPixmapBytes:
1009 return ProcXResQueryClientPixmapBytes(client);
1010 case X_XResQueryClientIds:
1011 return ProcXResQueryClientIds(client);
1012 case X_XResQueryResourceBytes:
1013 return ProcXResQueryResourceBytes(client);
1014 default: break;
1015 }
1016
1017 return BadRequest;
1018 }
1019
1020 static int _X_COLD
SProcXResQueryVersion(ClientPtr client)1021 SProcXResQueryVersion(ClientPtr client)
1022 {
1023 REQUEST_SIZE_MATCH(xXResQueryVersionReq);
1024 return ProcXResQueryVersion(client);
1025 }
1026
1027 static int _X_COLD
SProcXResQueryClientResources(ClientPtr client)1028 SProcXResQueryClientResources(ClientPtr client)
1029 {
1030 REQUEST(xXResQueryClientResourcesReq);
1031 REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
1032 swapl(&stuff->xid);
1033 return ProcXResQueryClientResources(client);
1034 }
1035
1036 static int _X_COLD
SProcXResQueryClientPixmapBytes(ClientPtr client)1037 SProcXResQueryClientPixmapBytes(ClientPtr client)
1038 {
1039 REQUEST(xXResQueryClientPixmapBytesReq);
1040 REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
1041 swapl(&stuff->xid);
1042 return ProcXResQueryClientPixmapBytes(client);
1043 }
1044
1045 static int _X_COLD
SProcXResQueryClientIds(ClientPtr client)1046 SProcXResQueryClientIds (ClientPtr client)
1047 {
1048 REQUEST(xXResQueryClientIdsReq);
1049
1050 REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
1051 swapl(&stuff->numSpecs);
1052 return ProcXResQueryClientIds(client);
1053 }
1054
1055 /** @brief Implements the XResQueryResourceBytes of XResProto v1.2.
1056 This variant byteswaps request contents before issuing the
1057 rest of the work to ProcXResQueryResourceBytes */
1058 static int _X_COLD
SProcXResQueryResourceBytes(ClientPtr client)1059 SProcXResQueryResourceBytes (ClientPtr client)
1060 {
1061 REQUEST(xXResQueryResourceBytesReq);
1062 int c;
1063 xXResResourceIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
1064
1065 REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
1066 swapl(&stuff->numSpecs);
1067 REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
1068 stuff->numSpecs * sizeof(specs[0]));
1069
1070 for (c = 0; c < stuff->numSpecs; ++c) {
1071 SwapXResResourceIdSpec(specs + c);
1072 }
1073
1074 return ProcXResQueryResourceBytes(client);
1075 }
1076
1077 static int _X_COLD
SProcResDispatch(ClientPtr client)1078 SProcResDispatch (ClientPtr client)
1079 {
1080 REQUEST(xReq);
1081 swaps(&stuff->length);
1082
1083 switch (stuff->data) {
1084 case X_XResQueryVersion:
1085 return SProcXResQueryVersion(client);
1086 case X_XResQueryClients: /* nothing to swap */
1087 return ProcXResQueryClients(client);
1088 case X_XResQueryClientResources:
1089 return SProcXResQueryClientResources(client);
1090 case X_XResQueryClientPixmapBytes:
1091 return SProcXResQueryClientPixmapBytes(client);
1092 case X_XResQueryClientIds:
1093 return SProcXResQueryClientIds(client);
1094 case X_XResQueryResourceBytes:
1095 return SProcXResQueryResourceBytes(client);
1096 default: break;
1097 }
1098
1099 return BadRequest;
1100 }
1101
1102 void
ResExtensionInit(void)1103 ResExtensionInit(void)
1104 {
1105 (void) AddExtension(XRES_NAME, 0, 0,
1106 ProcResDispatch, SProcResDispatch,
1107 NULL, StandardMinorOpcode);
1108 }
1109