~brandontschaefer/+junk/break-x

« back to all changes in this revision

Viewing changes to Xext/xres.c

  • Committer: Brandon Schaefer
  • Date: 2014-09-30 19:38:40 UTC
  • Revision ID: brandon.schaefer@canonical.com-20140930193840-a65z6qk8ze02cgsb
* Init commit to back this up

Show diffs side-by-side

added added

removed removed

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