xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xres.c (33230B)


      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 *
    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
    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
    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
    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
    157 DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
    158 {
    159     DestroyFragments(&ctx->response);
    160 }
    161 
    162 static Bool
    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
    187 DestroyConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx)
    188 {
    189     DestroyFragments(&ctx->response);
    190     ht_destroy(ctx->visitedResources);
    191 }
    192 
    193 static int
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    614 SwapXResResourceIdSpec(xXResResourceIdSpec *spec)
    615 {
    616     swapl(&spec->resource);
    617     swapl(&spec->type);
    618 }
    619 
    620 /** @brief Swaps xXResResourceSizeSpec endianness */
    621 static void
    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
    632 SwapXResResourceSizeValue(xXResResourceSizeValue *rep)
    633 {
    634     SwapXResResourceSizeSpec(&rep->size);
    635     swapl(&rep->numCrossReferences);
    636 }
    637 
    638 /** @brief Swaps the response bytes */
    639 static void
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   1021 SProcXResQueryVersion(ClientPtr client)
   1022 {
   1023     REQUEST_SIZE_MATCH(xXResQueryVersionReq);
   1024     return ProcXResQueryVersion(client);
   1025 }
   1026 
   1027 static int _X_COLD
   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
   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
   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
   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
   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
   1103 ResExtensionInit(void)
   1104 {
   1105     (void) AddExtension(XRES_NAME, 0, 0,
   1106                         ProcResDispatch, SProcResDispatch,
   1107                         NULL, StandardMinorOpcode);
   1108 }