xres.c revision 7e31ba66
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 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 216static int 217ProcXResQueryClients(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 269static void 270ResFindAllRes(void *value, XID id, RESTYPE type, void *cdata) 271{ 272 int *counts = (int *) cdata; 273 274 counts[(type & TypeMask) - 1]++; 275} 276 277static CARD32 278resourceTypeAtom(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 295static int 296ProcXResQueryClientResources(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 360static void 361ResFindResourcePixmaps(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 371static int 372ProcXResQueryClientPixmapBytes(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*/ 428static Bool 429WillConstructMask(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 endianess. 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*/ 456static Bool 457ConstructClientIdValue(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*/ 529static int 530ConstructClientIds(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*/ 570static int 571ProcXResQueryClientIds (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 endianess */ 613static void 614SwapXResResourceIdSpec(xXResResourceIdSpec *spec) 615{ 616 swapl(&spec->resource); 617 swapl(&spec->type); 618} 619 620/** @brief Swaps xXResResourceSizeSpec endianess */ 621static void 622SwapXResResourceSizeSpec(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 endianess */ 631static void 632SwapXResResourceSizeValue(xXResResourceSizeValue *rep) 633{ 634 SwapXResResourceSizeSpec(&rep->size); 635 swapl(&rep->numCrossReferences); 636} 637 638/** @brief Swaps the response bytes */ 639static void 640SwapXResQueryResourceBytes(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*/ 671static void 672AddSubResourceSizeSpec(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*/ 736static void 737AddResourceSizeValue(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*/ 806static void 807AddResourceSizeValueWithResType(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*/ 824static void 825AddResourceSizeValueByResource(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*/ 847static void 848ConstructClientResourceBytes(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*/ 881static void 882ConstructResourceBytesByResource(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*/ 911static int 912ConstructResourceBytes(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 */ 949static int 950ProcXResQueryResourceBytes (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 997static int 998ProcResDispatch(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 1020static int _X_COLD 1021SProcXResQueryVersion(ClientPtr client) 1022{ 1023 REQUEST_SIZE_MATCH(xXResQueryVersionReq); 1024 return ProcXResQueryVersion(client); 1025} 1026 1027static int _X_COLD 1028SProcXResQueryClientResources(ClientPtr client) 1029{ 1030 REQUEST(xXResQueryClientResourcesReq); 1031 REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq); 1032 swapl(&stuff->xid); 1033 return ProcXResQueryClientResources(client); 1034} 1035 1036static int _X_COLD 1037SProcXResQueryClientPixmapBytes(ClientPtr client) 1038{ 1039 REQUEST(xXResQueryClientPixmapBytesReq); 1040 REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq); 1041 swapl(&stuff->xid); 1042 return ProcXResQueryClientPixmapBytes(client); 1043} 1044 1045static int _X_COLD 1046SProcXResQueryClientIds (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 */ 1058static int _X_COLD 1059SProcXResQueryResourceBytes (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 1077static int _X_COLD 1078SProcResDispatch (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 1102void 1103ResExtensionInit(void) 1104{ 1105 (void) AddExtension(XRES_NAME, 0, 0, 1106 ProcResDispatch, SProcResDispatch, 1107 NULL, StandardMinorOpcode); 1108} 1109