Bug Summary

File:lib/rpmds.c
Warning:line 961, column 5
Value stored to 'i' is never read

Annotated Source Code

1/** \ingroup rpmdep
2 * \file lib/rpmds.c
3 */
4#include "system.h"
5
6#include <rpm/rpmtypes.h>
7#include <rpm/rpmlib.h> /* rpmvercmp */
8#include <rpm/rpmstring.h>
9#include <rpm/rpmlog.h>
10#include <rpm/rpmstrpool.h>
11
12#include "lib/rpmds_internal.h"
13
14#include "debug.h"
15
16int _rpmds_debug = 0;
17
18int _rpmds_nopromote = 1;
19
20/**
21 * A package dependency set.
22 */
23struct rpmds_s {
24 rpmstrPool pool; /*!< String pool. */
25 const char * Type; /*!< Tag name. */
26 char * DNEVR; /*!< Formatted dependency string. */
27 rpmsid * N; /*!< Dependency name id's (pool) */
28 rpmsid * EVR; /*!< Dependency EVR id's (pool) */
29 rpmsenseFlags * Flags; /*!< Bit(s) identifying context/comparison. */
30 rpm_color_t * Color; /*!< Bit(s) calculated from file color(s). */
31 rpmTagVal tagN; /*!< Header tag. */
32 int32_t Count; /*!< No. of elements */
33 unsigned int instance; /*!< From rpmdb instance? */
34 int i; /*!< Element index. */
35 int nopromote; /*!< Don't promote Epoch: in rpmdsCompare()? */
36 int nrefs; /*!< Reference count. */
37 int *ti; /*!< Trigger index. */
38};
39
40static int dsType(rpmTagVal tag,
41 const char ** Type, rpmTagVal * tagEVR, rpmTagVal * tagF,
42 rpmTagVal * tagTi)
43{
44 int rc = 0;
45 const char *t = NULL((void*)0);
46 rpmTagVal evr = RPMTAG_NOT_FOUND;
47 rpmTagVal f = RPMTAG_NOT_FOUND;
48 rpmTagVal ti = RPMTAG_NOT_FOUND;
49
50 if (tag == RPMTAG_PROVIDENAME) {
51 t = "Provides";
52 evr = RPMTAG_PROVIDEVERSION;
53 f = RPMTAG_PROVIDEFLAGS;
54 } else if (tag == RPMTAG_REQUIRENAME) {
55 t = "Requires";
56 evr = RPMTAG_REQUIREVERSION;
57 f = RPMTAG_REQUIREFLAGS;
58 } else if (tag == RPMTAG_SUPPLEMENTNAME) {
59 t = "Supplements";
60 evr = RPMTAG_SUPPLEMENTVERSION;
61 f = RPMTAG_SUPPLEMENTFLAGS;
62 } else if (tag == RPMTAG_ENHANCENAME) {
63 t = "Enhances";
64 evr = RPMTAG_ENHANCEVERSION;
65 f = RPMTAG_ENHANCEFLAGS;
66 } else if (tag == RPMTAG_RECOMMENDNAME) {
67 t = "Recommends";
68 evr = RPMTAG_RECOMMENDVERSION;
69 f = RPMTAG_RECOMMENDFLAGS;
70 } else if (tag == RPMTAG_SUGGESTNAME) {
71 t = "Suggests";
72 evr = RPMTAG_SUGGESTVERSION;
73 f = RPMTAG_SUGGESTFLAGS;
74 } else if (tag == RPMTAG_CONFLICTNAME) {
75 t = "Conflicts";
76 evr = RPMTAG_CONFLICTVERSION;
77 f = RPMTAG_CONFLICTFLAGS;
78 } else if (tag == RPMTAG_OBSOLETENAME) {
79 t = "Obsoletes";
80 evr = RPMTAG_OBSOLETEVERSION;
81 f = RPMTAG_OBSOLETEFLAGS;
82 } else if (tag == RPMTAG_ORDERNAME) {
83 t = "Order";
84 evr = RPMTAG_ORDERVERSION;
85 f = RPMTAG_ORDERFLAGS;
86 } else if (tag == RPMTAG_TRIGGERNAME) {
87 t = "Trigger";
88 evr = RPMTAG_TRIGGERVERSION;
89 f = RPMTAG_TRIGGERFLAGS;
90 ti = RPMTAG_TRIGGERINDEX;
91 } else if (tag == RPMTAG_OLDSUGGESTSNAME) {
92 t = "Oldsuggests";
93 evr = RPMTAG_OLDSUGGESTSVERSION;
94 f = RPMTAG_OLDSUGGESTSFLAGS;
95 } else if (tag == RPMTAG_OLDENHANCESNAME) {
96 t = "Oldenhances";
97 evr = RPMTAG_OLDENHANCESVERSION;
98 f = RPMTAG_OLDENHANCESFLAGS;
99 } else if (tag == RPMTAG_FILETRIGGERNAME) {
100 t = "FileTrigger";
101 evr = RPMTAG_FILETRIGGERVERSION;
102 f = RPMTAG_FILETRIGGERFLAGS;
103 ti = RPMTAG_FILETRIGGERINDEX;
104 } else if (tag == RPMTAG_TRANSFILETRIGGERNAME) {
105 t = "TransFileTrigger";
106 evr = RPMTAG_TRANSFILETRIGGERVERSION;
107 f = RPMTAG_TRANSFILETRIGGERFLAGS;
108 ti = RPMTAG_TRANSFILETRIGGERINDEX;
109 } else {
110 rc = 1;
111 }
112 if (Type) *Type = t;
113 if (tagEVR) *tagEVR = evr;
114 if (tagF) *tagF = f;
115 if (tagTi) *tagTi = ti;
116 return rc;
117}
118
119static char tagNToChar(rpmTagVal tagN)
120{
121 switch (tagN) {
122 default:
123 return 'R';
124 break;
125 case RPMTAG_REQUIRENAME:
126 return 'R';
127 break;
128 case RPMTAG_PROVIDENAME:
129 return 'P';
130 break;
131 case RPMTAG_RECOMMENDNAME:
132 return 'r';
133 break;
134 case RPMTAG_SUGGESTNAME:
135 return 's';
136 break;
137 case RPMTAG_SUPPLEMENTNAME:
138 return 'S';
139 break;
140 case RPMTAG_ENHANCENAME:
141 return 'e';
142 break;
143 case RPMTAG_CONFLICTNAME:
144 return 'C';
145 break;
146 case RPMTAG_OBSOLETENAME:
147 return 'O';
148 break;
149 }
150}
151
152rpmTagVal rpmdsDToTagN(char deptype)
153{
154 rpmTagVal tagN = RPMTAG_REQUIRENAME;
155 switch (deptype) {
156 default:
157 tagN = RPMTAG_NOT_FOUND;
158 break;
159 case 'P':
160 tagN = RPMTAG_PROVIDENAME;
161 break;
162 case 'R':
163 tagN = RPMTAG_REQUIRENAME;
164 break;
165 case 'r':
166 tagN = RPMTAG_RECOMMENDNAME;
167 break;
168 case 's':
169 tagN = RPMTAG_SUGGESTNAME;
170 break;
171 case 'S':
172 tagN = RPMTAG_SUPPLEMENTNAME;
173 break;
174 case 'e':
175 tagN = RPMTAG_ENHANCENAME;
176 break;
177 case 'C':
178 tagN = RPMTAG_CONFLICTNAME;
179 break;
180 case 'O':
181 tagN = RPMTAG_OBSOLETENAME;
182 break;
183 }
184 return tagN;
185}
186
187rpmsid rpmdsNIdIndex(rpmds ds, int i)
188{
189 rpmsid id = 0;
190 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->N != NULL((void*)0))
191 id = ds->N[i];
192 return id;
193}
194
195rpmsid rpmdsEVRIdIndex(rpmds ds, int i)
196{
197 rpmsid id = 0;
198 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->EVR != NULL((void*)0))
199 id = ds->EVR[i];
200 return id;
201}
202const char * rpmdsNIndex(rpmds ds, int i)
203{
204 const char * N = NULL((void*)0);
205 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->N != NULL((void*)0))
206 N = rpmstrPoolStr(ds->pool, ds->N[i]);
207 return N;
208}
209
210const char * rpmdsEVRIndex(rpmds ds, int i)
211{
212 const char * EVR = NULL((void*)0);
213 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->EVR != NULL((void*)0))
214 EVR = rpmstrPoolStr(ds->pool, ds->EVR[i]);
215 return EVR;
216}
217
218rpmsenseFlags rpmdsFlagsIndex(rpmds ds, int i)
219{
220 rpmsenseFlags Flags = 0;
221 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->Flags != NULL((void*)0))
222 Flags = ds->Flags[i];
223 return Flags;
224}
225
226int rpmdsTiIndex(rpmds ds, int i)
227{
228 int ti = -1;
229 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->ti != NULL((void*)0))
230 ti = ds->ti[i];
231 return ti;
232}
233
234rpm_color_t rpmdsColorIndex(rpmds ds, int i)
235{
236 rpm_color_t Color = 0;
237 if (ds != NULL((void*)0) && i >= 0 && i < ds->Count && ds->Color != NULL((void*)0))
238 Color = ds->Color[i];
239 return Color;
240}
241static rpmds rpmdsUnlink(rpmds ds)
242{
243 if (ds)
244 ds->nrefs--;
245 return NULL((void*)0);
246}
247
248rpmds rpmdsLink(rpmds ds)
249{
250 if (ds)
251 ds->nrefs++;
252 return ds;
253}
254
255rpmds rpmdsFree(rpmds ds)
256{
257 rpmTagVal tagEVR, tagF, tagTi;
258
259 if (ds == NULL((void*)0))
260 return NULL((void*)0);
261
262 if (ds->nrefs > 1)
263 return rpmdsUnlink(ds);
264
265 if (dsType(ds->tagN, NULL((void*)0), &tagEVR, &tagF, &tagTi))
266 return NULL((void*)0);
267
268 if (ds->Count > 0) {
269 ds->N = _free(ds->N)rfree((ds->N));
270 ds->EVR = _free(ds->EVR)rfree((ds->EVR));
271 ds->Flags = _free(ds->Flags)rfree((ds->Flags));
272 ds->ti = _free(ds->ti)rfree((ds->ti));
273 }
274
275 ds->pool = rpmstrPoolFree(ds->pool);
276 ds->DNEVR = _free(ds->DNEVR)rfree((ds->DNEVR));
277 ds->Color = _free(ds->Color)rfree((ds->Color));
278
279 (void) rpmdsUnlink(ds);
280 memset(ds, 0, sizeof(*ds)); /* XXX trash and burn */
281 ds = _free(ds)rfree((ds));
282 return NULL((void*)0);
283}
284
285static rpmds rpmdsCreate(rpmstrPool pool,
286 rpmTagVal tagN, const char * Type, int Count,
287 unsigned int instance)
288{
289 rpmds ds = xcalloc(1, sizeof(*ds))rcalloc((1), (sizeof(*ds)));
290
291 ds->pool = (pool != NULL((void*)0)) ? rpmstrPoolLink(pool) : rpmstrPoolCreate();
292 ds->tagN = tagN;
293 ds->Type = Type;
294 ds->Count = Count;
295 ds->instance = instance;
296 ds->nopromote = _rpmds_nopromote;
297 ds->i = -1;
298
299 return rpmdsLink(ds);
300}
301
302rpmds rpmdsNewPool(rpmstrPool pool, Header h, rpmTagVal tagN, int flags)
303{
304 rpmTagVal tagEVR, tagF, tagTi;
305 rpmds ds = NULL((void*)0);
306 const char * Type;
307 struct rpmtd_s names;
308 if (dsType(tagN, &Type, &tagEVR, &tagF, &tagTi))
309 goto exit;
310
311 if (headerGet(h, tagN, &names, HEADERGET_MINMEM)) {
312 struct rpmtd_s evr, flags, tindices;
313 rpm_count_t count = rpmtdCount(&names);
314
315 headerGet(h, tagEVR, &evr, HEADERGET_MINMEM);
316 if (evr.count && evr.count != count) {
317 rpmtdFreeData(&evr);
318 return NULL((void*)0);
319 }
320
321 headerGet(h, tagF, &flags, HEADERGET_ALLOC);
322 if (flags.count && flags.count != count) {
323 rpmtdFreeData(&flags);
324 return NULL((void*)0);
325 }
326
327 if (tagTi != RPMTAG_NOT_FOUND) {
328 headerGet(h, tagTi, &tindices, HEADERGET_ALLOC);
329 if (tindices.count && tindices.count != count) {
330 rpmtdFreeData(&tindices);
331 return NULL((void*)0);
332 }
333 }
334
335 ds = rpmdsCreate(pool, tagN, Type, count, headerGetInstance(h));
336
337 ds->N = names.count ? rpmtdToPool(&names, ds->pool) : NULL((void*)0);
338 ds->EVR = evr.count ? rpmtdToPool(&evr, ds->pool): NULL((void*)0);
339 ds->Flags = flags.data;
340 if (tagTi != RPMTAG_NOT_FOUND) {
341 ds->ti = tindices.data;
342 }
343
344 /* ensure rpmlib() requires always have RPMSENSE_RPMLIB flag set */
345 if (tagN == RPMTAG_REQUIRENAME && ds->Flags) {
346 for (int i = 0; i < ds->Count; i++) {
347 if (!(rpmdsFlagsIndex(ds, i) & RPMSENSE_RPMLIB)) {
348 const char *N = rpmdsNIndex(ds, i);
349 if (rstreqn(N, "rpmlib(", sizeof("rpmlib(")-1))
350 ds->Flags[i] |= RPMSENSE_RPMLIB;
351 }
352 }
353 }
354 rpmtdFreeData(&names);
355 rpmtdFreeData(&evr);
356
357 /* freeze the pool to save memory, but only if private pool */
358 if (ds->pool != pool)
359 rpmstrPoolFreeze(ds->pool, 0);
360 }
361
362exit:
363 return ds;
364}
365
366rpmds rpmdsNew(Header h, rpmTagVal tagN, int flags)
367{
368 return rpmdsNewPool(NULL((void*)0), h, tagN, flags);
369}
370
371char * rpmdsNewDNEVR(const char * dspfx, const rpmds ds)
372{
373 const char * N = rpmdsN(ds);
374 const char * EVR = rpmdsEVR(ds);
375 rpmsenseFlags Flags = rpmdsFlags(ds);
376 char * tbuf, * t;
377 size_t nb;
378
379 nb = 0;
380 if (dspfx) nb += strlen(dspfx) + 1;
381 if (N) nb += strlen(N);
382 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
383 if (Flags & RPMSENSE_SENSEMASK15) {
384 if (nb) nb++;
385 if (Flags & RPMSENSE_LESS) nb++;
386 if (Flags & RPMSENSE_GREATER) nb++;
387 if (Flags & RPMSENSE_EQUAL) nb++;
388 }
389 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
390 if (EVR && *EVR) {
391 if (nb) nb++;
392 nb += strlen(EVR);
393 }
394
395 t = tbuf = xmalloc(nb + 1)rmalloc((nb + 1));
396 if (dspfx) {
397 t = stpcpy(t, dspfx);
398 *t++ = ' ';
399 }
400 if (N)
401 t = stpcpy(t, N);
402 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
403 if (Flags & RPMSENSE_SENSEMASK15) {
404 if (t != tbuf) *t++ = ' ';
405 if (Flags & RPMSENSE_LESS) *t++ = '<';
406 if (Flags & RPMSENSE_GREATER) *t++ = '>';
407 if (Flags & RPMSENSE_EQUAL) *t++ = '=';
408 }
409 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
410 if (EVR && *EVR) {
411 if (t != tbuf) *t++ = ' ';
412 t = stpcpy(t, EVR);
413 }
414 *t = '\0';
415 return tbuf;
416}
417
418static rpmds singleDSPool(rpmstrPool pool, rpmTagVal tagN,
419 rpmsid N, rpmsid EVR, rpmsenseFlags Flags,
420 unsigned int instance, rpm_color_t Color,
421 int triggerIndex)
422{
423 rpmds ds = NULL((void*)0);
424 const char * Type;
425 rpmTagVal tagTi;
426
427 if (dsType(tagN, &Type, NULL((void*)0), NULL((void*)0), &tagTi))
428 goto exit;
429
430 ds = rpmdsCreate(pool, tagN, Type, 1, instance);
431
432 ds->N = xmalloc(1 * sizeof(*ds->N))rmalloc((1 * sizeof(*ds->N)));
433 ds->N[0] = N;
434 ds->EVR = xmalloc(1 * sizeof(*ds->EVR))rmalloc((1 * sizeof(*ds->EVR)));
435 ds->EVR[0] = EVR;
436 ds->Flags = xmalloc(sizeof(*ds->Flags))rmalloc((sizeof(*ds->Flags)));
437 ds->Flags[0] = Flags;
438 if (tagTi != RPMTAG_NOT_FOUND) {
439 ds->ti = xmalloc(sizeof(*ds->ti))rmalloc((sizeof(*ds->ti)));
440 ds->ti[0] = triggerIndex;
441 }
442 ds->i = 0;
443 if (Color)
444 rpmdsSetColor(ds, Color);
445
446exit:
447 return ds;
448}
449
450static rpmds singleDS(rpmstrPool pool, rpmTagVal tagN,
451 const char * N, const char * EVR,
452 rpmsenseFlags Flags, unsigned int instance,
453 rpm_color_t Color, int triggerIndex)
454{
455 rpmds ds = singleDSPool(pool, tagN, 0, 0, Flags, instance, Color,
456 triggerIndex);
457 if (ds) {
458 /* now that we have a pool, we can insert our N & EVR strings */
459 ds->N[0] = rpmstrPoolId(ds->pool, N ? N : "", 1);
460 ds->EVR[0] = rpmstrPoolId(ds->pool, EVR ? EVR : "", 1);
461 /* freeze the pool to save memory, but only if private pool */
462 if (ds->pool != pool)
463 rpmstrPoolFreeze(ds->pool, 0);
464 }
465 return ds;
466}
467
468rpmds rpmdsThisPool(rpmstrPool pool,
469 Header h, rpmTagVal tagN, rpmsenseFlags Flags)
470{
471 char *evr = headerGetAsString(h, RPMTAG_EVR);
472 rpmds ds = singleDS(pool, tagN, headerGetString(h, RPMTAG_NAME),
473 evr, Flags, headerGetInstance(h), 0, 0);
474 free(evr);
475 return ds;
476}
477
478rpmds rpmdsThis(Header h, rpmTagVal tagN, rpmsenseFlags Flags)
479{
480 return rpmdsThisPool(NULL((void*)0), h, tagN, Flags);
481}
482
483rpmds rpmdsSinglePool(rpmstrPool pool,rpmTagVal tagN,
484 const char * N, const char * EVR, rpmsenseFlags Flags)
485{
486 return singleDS(pool, tagN, N, EVR, Flags, 0, 0, 0);
487}
488
489rpmds rpmdsSinglePoolTix(rpmstrPool pool,rpmTagVal tagN,
490 const char * N, const char * EVR,
491 rpmsenseFlags Flags, int triggerIndex)
492{
493 return singleDS(pool, tagN, N, EVR, Flags, 0, 0, triggerIndex);
494}
495
496rpmds rpmdsSingle(rpmTagVal tagN, const char * N, const char * EVR, rpmsenseFlags Flags)
497{
498 return rpmdsSinglePool(NULL((void*)0), tagN, N, EVR, Flags);
499}
500
501rpmds rpmdsCurrent(rpmds ds)
502{
503 rpmds cds = NULL((void*)0);
504 int ti = -1;
505 if (ds != NULL((void*)0) && ds->i >= 0 && ds->i < ds->Count) {
506 if (ds->ti)
507 ti = ds->ti[ds->i];
508 /* Using parent's pool so we can just use the same id's */
509 cds = singleDSPool(ds->pool, ds->tagN, ds->N[ds->i], ds->EVR[ds->i],
510 rpmdsFlags(ds), ds->instance, rpmdsColor(ds), ti);
511 }
512 return cds;
513}
514
515rpmds rpmdsFilterTi(rpmds ds, int ti)
516{
517 int i, i2, tiCount = 0;
518 rpmds fds;
519
520 if (ds == NULL((void*)0) || !ds->ti || !ds->Count)
521 return NULL((void*)0);
522
523 for (i = 0; i < ds->Count; i++) {
524 if (ds->ti[i] == ti)
525 tiCount++;
526 }
527
528 if (!tiCount)
529 return NULL((void*)0);
530
531 fds = rpmdsCreate(ds->pool, ds->tagN, ds->Type, tiCount, ds->instance);
532
533 fds->N = xmalloc(tiCount * sizeof(*fds->N))rmalloc((tiCount * sizeof(*fds->N)));
534 fds->EVR = xmalloc(tiCount * sizeof(*fds->EVR))rmalloc((tiCount * sizeof(*fds->EVR)));
535 fds->Flags = xmalloc(tiCount * sizeof(*fds->Flags))rmalloc((tiCount * sizeof(*fds->Flags)));
536 fds->ti = xmalloc(tiCount * sizeof(*fds->ti))rmalloc((tiCount * sizeof(*fds->ti)));
537 fds->i = -1;
538
539 i2 = 0;
540 for (i = 0; i < ds->Count; i++) {
541 if (ds->ti[i] == ti) {
542 fds->N[i2] = ds->N[i];
543 fds->EVR[i2] = ds->EVR[i];
544 fds->Flags[i2] = ds->Flags[i];
545 fds->ti[i2] = ds->ti[i];
546 i2++;
547 }
548 }
549
550 return fds;
551}
552
553int rpmdsPutToHeader(rpmds ds, Header h)
554{
555 rpmTagVal tagN = rpmdsTagN(ds);
556 rpmTagVal tagEVR = rpmdsTagEVR(ds);
557 rpmTagVal tagF = rpmdsTagF(ds);
558 rpmTagVal tagTi = rpmdsTagTi(ds);
559 if (!tagN)
560 return -1;
561
562 rpmds pi = rpmdsInit(ds);
563 while (rpmdsNext(pi) >= 0) {
564 rpmsenseFlags flags = rpmdsFlags(pi);
565 uint32_t index = rpmdsTi(pi);
566 headerPutString(h, tagN, rpmdsN(pi));
567 headerPutString(h, tagEVR, rpmdsEVR(pi));
568 headerPutUint32(h, tagF, &flags, 1);
569 if (tagTi != RPMTAG_NOT_FOUND) {
570 headerPutUint32(h, tagTi, &index, 1);
571 }
572 }
573 return 0;
574}
575
576int rpmdsCount(const rpmds ds)
577{
578 return (ds != NULL((void*)0) ? ds->Count : 0);
579}
580
581int rpmdsIx(const rpmds ds)
582{
583 return (ds != NULL((void*)0) ? ds->i : -1);
584}
585
586int rpmdsSetIx(rpmds ds, int ix)
587{
588 int i = -1;
589
590 if (ds != NULL((void*)0)) {
591 i = ds->i;
592 ds->i = ix;
593 ds->DNEVR = _free(ds->DNEVR)rfree((ds->DNEVR));
594 }
595 return i;
596}
597
598char rpmdsD(const rpmds ds)
599{
600 if (ds != NULL((void*)0)) {
601 return tagNToChar(ds->tagN);
602 } else {
603 return '\0';
604 }
605}
606
607const char * rpmdsDNEVR(const rpmds ds)
608{
609 const char * DNEVR = NULL((void*)0);
610
611 if (ds != NULL((void*)0) && ds->i >= 0 && ds->i < ds->Count) {
612 if (ds->DNEVR == NULL((void*)0)) {
613 char t[2] = { tagNToChar(ds->tagN), '\0' };
614 ds->DNEVR = rpmdsNewDNEVR(t, ds);
615 }
616 DNEVR = ds->DNEVR;
617 }
618 return DNEVR;
619}
620
621rpmsid rpmdsNId(rpmds ds)
622{
623 return (ds != NULL((void*)0)) ? rpmdsNIdIndex(ds, ds->i) : 0;
624}
625
626rpmsid rpmdsEVRId(rpmds ds)
627{
628 return (ds != NULL((void*)0)) ? rpmdsEVRIdIndex(ds, ds->i) : 0;
629}
630
631const char * rpmdsN(const rpmds ds)
632{
633 return (ds != NULL((void*)0)) ? rpmdsNIndex(ds, ds->i) : NULL((void*)0);
634}
635
636const char * rpmdsEVR(const rpmds ds)
637{
638 return (ds != NULL((void*)0)) ? rpmdsEVRIndex(ds, ds->i) : NULL((void*)0);
639}
640
641rpmsenseFlags rpmdsFlags(const rpmds ds)
642{
643 return (ds != NULL((void*)0)) ? rpmdsFlagsIndex(ds, ds->i) : 0;
644}
645
646int rpmdsTi(const rpmds ds)
647{
648 return (ds != NULL((void*)0)) ? rpmdsTiIndex(ds, ds->i) : 0;
649}
650
651rpmTagVal rpmdsTagN(const rpmds ds)
652{
653 rpmTagVal tagN = RPMTAG_NOT_FOUND;
654
655 if (ds != NULL((void*)0))
656 tagN = ds->tagN;
657 return tagN;
658}
659
660rpmTagVal rpmdsTagEVR(const rpmds ds)
661{
662 rpmTagVal tagEVR = RPMTAG_NOT_FOUND;
663
664 if (ds != NULL((void*)0))
665 dsType(ds->tagN, NULL((void*)0), &tagEVR, NULL((void*)0), NULL((void*)0));
666 return tagEVR;
667}
668
669rpmTagVal rpmdsTagF(const rpmds ds)
670{
671 rpmTagVal tagF = RPMTAG_NOT_FOUND;
672
673 if (ds != NULL((void*)0))
674 dsType(ds->tagN, NULL((void*)0), NULL((void*)0), &tagF, NULL((void*)0));
675 return tagF;
676}
677
678rpmTagVal rpmdsTagTi(const rpmds ds)
679{
680 rpmTagVal tagTi = RPMTAG_NOT_FOUND;
681
682 if (ds != NULL((void*)0))
683 dsType(ds->tagN, NULL((void*)0), NULL((void*)0), NULL((void*)0), &tagTi);
684 return tagTi;
685}
686
687unsigned int rpmdsInstance(rpmds ds)
688{
689 return (ds != NULL((void*)0)) ? ds->instance : 0;
690}
691
692int rpmdsNoPromote(const rpmds ds)
693{
694 int nopromote = 0;
695
696 if (ds != NULL((void*)0))
697 nopromote = ds->nopromote;
698 return nopromote;
699}
700
701int rpmdsSetNoPromote(rpmds ds, int nopromote)
702{
703 int onopromote = 0;
704
705 if (ds != NULL((void*)0)) {
706 onopromote = ds->nopromote;
707 ds->nopromote = nopromote;
708 }
709 return onopromote;
710}
711
712rpm_color_t rpmdsColor(const rpmds ds)
713{
714 return (ds != NULL((void*)0)) ? rpmdsColorIndex(ds, ds->i) : 0;
715}
716
717rpm_color_t rpmdsSetColor(const rpmds ds, rpm_color_t color)
718{
719 rpm_color_t ocolor = 0;
720
721 if (ds != NULL((void*)0) && ds->i >= 0 && ds->i < ds->Count) {
722 if (ds->Color == NULL((void*)0)) {
723 ds->Color = xcalloc(ds->Count, sizeof(*ds->Color))rcalloc((ds->Count), (sizeof(*ds->Color)));
724 }
725 ocolor = ds->Color[ds->i];
726 ds->Color[ds->i] = color;
727 }
728 return ocolor;
729}
730
731void rpmdsNotify(rpmds ds, const char * where, int rc)
732{
733 const char *DNEVR;
734
735 if (!rpmIsDebug()(rpmlogSetMask(0) >= (1 << ((unsigned)(RPMLOG_DEBUG)
)))
)
736 return;
737 if (!(ds != NULL((void*)0) && ds->i >= 0 && ds->i < ds->Count))
738 return;
739 if (!(ds->Type != NULL((void*)0) && (DNEVR = rpmdsDNEVR(ds)) != NULL((void*)0)))
740 return;
741
742 rpmlog(RPMLOG_DEBUG, "%9s: %-45s %-s %s\n", ds->Type,
743 (rstreq(DNEVR, "cached") ? DNEVR : DNEVR+2),
744 (rc ? _("NO ")dcgettext ("rpm", "NO ", 5) : _("YES")dcgettext ("rpm", "YES", 5)),
745 (where != NULL((void*)0) ? where : ""));
746}
747
748int rpmdsNext(rpmds ds)
749{
750 int i = -1;
751
752 if (ds != NULL((void*)0) && ++ds->i >= 0) {
753 if (ds->i < ds->Count) {
754 i = ds->i;
755 ds->DNEVR = _free(ds->DNEVR)rfree((ds->DNEVR));
756 } else
757 ds->i = -1;
758
759if (_rpmds_debug < 0 && i != -1)
760fprintf(stderrstderr, "*** ds %p\t%s[%d]: %s\n", ds, (ds->Type ? ds->Type : "?Type?"), i, (ds->DNEVR ? ds->DNEVR : "?DNEVR?"));
761
762 }
763
764 return i;
765}
766
767rpmds rpmdsInit(rpmds ds)
768{
769 if (ds != NULL((void*)0)) {
770 ds->i = -1;
771 ds->DNEVR = _free(ds->DNEVR)rfree((ds->DNEVR));
772 }
773 return ds;
774}
775
776static rpmds rpmdsDup(const rpmds ods)
777{
778 rpmds ds = rpmdsCreate(ods->pool, ods->tagN, ods->Type,
779 ods->Count, ods->instance);
780 size_t nb;
781
782 ds->i = ods->i;
783 ds->nopromote = ods->nopromote;
784
785 nb = ds->Count * sizeof(*ds->N);
786 ds->N = memcpy(xmalloc(nb)rmalloc((nb)), ods->N, nb);
787
788 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
789 if (ods->EVR) {
790 nb = ds->Count * sizeof(*ds->EVR);
791 ds->EVR = memcpy(xmalloc(nb)rmalloc((nb)), ods->EVR, nb);
792 }
793
794 if (ods->Flags) {
795 nb = ds->Count * sizeof(*ds->Flags);
796 ds->Flags = memcpy(xmalloc(nb)rmalloc((nb)), ods->Flags, nb);
797 }
798
799 if (ods->ti) {
800 nb = ds->Count * sizeof(*ds->ti);
801 ds->ti = memcpy(xmalloc(nb)rmalloc((nb)), ods->ti, nb);
802 }
803
804 return ds;
805
806}
807
808static int doFind(rpmds ds, const rpmds ods, unsigned int *he)
809{
810 int comparison;
811 const char *N, *ON = rpmdsN(ods);
812 const char *EVR, *OEVR = rpmdsEVR(ods);
813 rpmsenseFlags Flags, OFlags = rpmdsFlags(ods);
814 int index, Oindex = rpmdsTi(ods);
815 int rc = -1; /* assume not found */
816
817 if (ds == NULL((void*)0) || ods == NULL((void*)0))
818 return -1;
819
820 unsigned int l = 0;
821 unsigned int u = ds->Count;
822 while (l < u) {
823 ds->i = (l + u) / 2;
824
825 N = rpmdsN(ds);
826 EVR = rpmdsEVR(ds);
827 Flags = rpmdsFlags(ds);
828 index = rpmdsTi(ds);
829
830 comparison = strcmp(ON, N);
831
832 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
833 if (comparison == 0 && OEVR && EVR)
834 comparison = strcmp(OEVR, EVR);
835 if (comparison == 0)
836 comparison = OFlags - Flags;
837 if (comparison == 0)
838 comparison = Oindex - index;
839
840 if (comparison < 0)
841 u = ds->i;
842 else if (comparison > 0)
843 l = ds->i + 1;
844 else {
845 rc = ds->i;
846 break;
847 }
848 }
849 if (he)
850 *he = u;
851 return rc;
852}
853
854int rpmdsFind(rpmds ds, const rpmds ods)
855{
856 return doFind(ds, ods, NULL((void*)0));
857}
858
859int rpmdsMerge(rpmds * dsp, rpmds ods)
860{
861 rpmds ds;
862 int save;
863 int ocount;
864
865 if (dsp == NULL((void*)0) || ods == NULL((void*)0))
866 return -1;
867
868 ocount = rpmdsCount(*dsp);
869
870 /* If not initialized yet, dup the 1st entry. */
871 if (*dsp == NULL((void*)0)) {
872 save = ods->Count;
873 ods->Count = 1;
874 *dsp = rpmdsDup(ods);
875 ods->Count = save;
876 }
877 ds = *dsp;
878 if (ds == NULL((void*)0))
879 return -1;
880
881 /* Ensure EVR and Flags exist */
882 if (ds->EVR == NULL((void*)0))
883 ds->EVR = xcalloc(ds->Count, sizeof(*ds->EVR))rcalloc((ds->Count), (sizeof(*ds->EVR)));
884 if (ds->Flags == NULL((void*)0))
885 ds->Flags = xcalloc(ds->Count, sizeof(*ds->Flags))rcalloc((ds->Count), (sizeof(*ds->Flags)));
886 if (ds->ti == NULL((void*)0) && ods->ti) {
887 int i;
888 ds->ti = xcalloc(ds->Count, sizeof(*ds->ti))rcalloc((ds->Count), (sizeof(*ds->ti)));
889 for (i = 0; i < ds->Count; i++)
890 ds->ti[i] = -1;
891 }
892
893 /*
894 * Add new entries.
895 */
896 save = ods->i;
897 ods = rpmdsInit(ods);
898 while (rpmdsNext(ods) >= 0) {
899 const char *OEVR;
900 unsigned int u;
901 /*
902 * If this entry is already present, don't bother.
903 */
904 if (doFind(ds, ods, &u) >= 0)
905 continue;
906
907 /*
908 * Insert new entry. Ensure pool is unfrozen to allow additions.
909 */
910 rpmstrPoolUnfreeze(ds->pool);
911 ds->N = xrealloc(ds->N, (ds->Count+1) * sizeof(*ds->N))rrealloc((ds->N), ((ds->Count+1) * sizeof(*ds->N)));
912 if (u < ds->Count) {
913 memmove(ds->N + u + 1, ds->N + u,
914 (ds->Count - u) * sizeof(*ds->N));
915 }
916 ds->N[u] = rpmstrPoolId(ds->pool, rpmdsN(ods), 1);
917
918 ds->EVR = xrealloc(ds->EVR, (ds->Count+1) * sizeof(*ds->EVR))rrealloc((ds->EVR), ((ds->Count+1) * sizeof(*ds->EVR
)))
;
919 if (u < ds->Count) {
920 memmove(ds->EVR + u + 1, ds->EVR + u,
921 (ds->Count - u) * sizeof(*ds->EVR));
922 }
923 OEVR = rpmdsEVR(ods);
924 ds->EVR[u] = rpmstrPoolId(ds->pool, OEVR ? OEVR : "", 1);
925
926 ds->Flags = xrealloc(ds->Flags, (ds->Count+1) * sizeof(*ds->Flags))rrealloc((ds->Flags), ((ds->Count+1) * sizeof(*ds->Flags
)))
;
927 if (u < ds->Count) {
928 memmove(ds->Flags + u + 1, ds->Flags + u,
929 (ds->Count - u) * sizeof(*ds->Flags));
930 }
931 ds->Flags[u] = rpmdsFlags(ods);
932
933 if (ds->ti || ods->ti) {
934 ds->ti = xrealloc(ds->ti, (ds->Count+1) * sizeof(*ds->ti))rrealloc((ds->ti), ((ds->Count+1) * sizeof(*ds->ti))
)
;
935 if (u < ds->Count) {
936 memmove(ds->ti + u + 1, ds->ti + u,
937 (ds->Count - u) * sizeof(*ds->ti));
938 }
939 ds->ti[u] = rpmdsTi(ods);
940 }
941
942 ds->i = ds->Count;
943 ds->Count++;
944
945 }
946 ods->i = save;
947 return (ds->Count - ocount);
948}
949
950
951int rpmdsSearch(rpmds ds, rpmds ods)
952{
953 int comparison;
954 int i, l, u;
955 const char *ON = rpmdsN(ods);
956
957 if (ds == NULL((void*)0) || ods == NULL((void*)0))
958 return -1;
959
960 /* Binary search to find the [l,u) subset that contains N */
961 i = -1;
Value stored to 'i' is never read
962 l = 0;
963 u = ds->Count;
964 while (l < u) {
965 i = (l + u) / 2;
966
967 comparison = strcmp(ON, rpmdsNIndex(ds, i));
968
969 if (comparison < 0)
970 u = i;
971 else if (comparison > 0)
972 l = i + 1;
973 else {
974 /* Set l to 1st member of set that contains N. */
975 if (!rstreq(ON, rpmdsNIndex(ds, l)))
976 l = i;
977 while (l > 0 && rstreq(ON, rpmdsNIndex(ds, l-1)))
978 l--;
979 /* Set u to 1st member of set that does not contain N. */
980 if (u >= ds->Count || !rstreq(ON, rpmdsNIndex(ds, u)))
981 u = i;
982 while (++u < ds->Count) {
983 if (!rstreq(ON, rpmdsNIndex(ds, u)))
984 break;
985 }
986 break;
987 }
988 }
989
990 /* Check each member of [l,u) subset for ranges overlap. */
991 i = -1;
992 if (l < u) {
993 int save = rpmdsSetIx(ds, l-1);
994 while ((l = rpmdsNext(ds)) >= 0 && (l < u)) {
995 if ((i = rpmdsCompare(ods, ds)) != 0)
996 break;
997 }
998 /* Return element index that overlaps, or -1. */
999 if (i)
1000 i = rpmdsIx(ds);
1001 else {
1002 (void) rpmdsSetIx(ds, save);
1003 i = -1;
1004 }
1005 }
1006 return i;
1007}
1008/**
1009 * Split EVR into epoch, version, and release components.
1010 * @param evr [epoch:]version[-release] string
1011 * @retval *ep pointer to epoch
1012 * @retval *vp pointer to version
1013 * @retval *rp pointer to release
1014 */
1015static
1016void parseEVR(char * evr,
1017 const char ** ep,
1018 const char ** vp,
1019 const char ** rp)
1020{
1021 const char *epoch;
1022 const char *version; /* assume only version is present */
1023 const char *release;
1024 char *s, *se;
1025
1026 s = evr;
1027 while (*s && risdigit(*s)) s++; /* s points to epoch terminator */
1028 se = strrchr(s, '-'); /* se points to version terminator */
1029
1030 if (*s == ':') {
1031 epoch = evr;
1032 *s++ = '\0';
1033 version = s;
1034 if (*epoch == '\0') epoch = "0";
1035 } else {
1036 epoch = NULL((void*)0); /* XXX disable epoch compare if missing */
1037 version = evr;
1038 }
1039 if (se) {
1040 *se++ = '\0';
1041 release = se;
1042 } else {
1043 release = NULL((void*)0);
1044 }
1045
1046 if (ep) *ep = epoch;
1047 if (vp) *vp = version;
1048 if (rp) *rp = release;
1049}
1050
1051static inline int rpmdsCompareEVR(const char *AEVR, uint32_t AFlags,
1052 const char *BEVR, uint32_t BFlags,
1053 int nopromote)
1054{
1055 const char *aE, *aV, *aR, *bE, *bV, *bR;
1056 char *aEVR = xstrdup(AEVR)rstrdup((AEVR));
1057 char *bEVR = xstrdup(BEVR)rstrdup((BEVR));
1058 int sense = 0;
1059 int result = 0;
1060
1061 parseEVR(aEVR, &aE, &aV, &aR);
1062 parseEVR(bEVR, &bE, &bV, &bR);
1063
1064 /* Compare {A,B} [epoch:]version[-release] */
1065 if (aE && *aE && bE && *bE)
1066 sense = rpmvercmp(aE, bE);
1067 else if (aE && *aE && atol(aE) > 0) {
1068 if (!nopromote) {
1069 sense = 0;
1070 } else
1071 sense = 1;
1072 } else if (bE && *bE && atol(bE) > 0)
1073 sense = -1;
1074
1075 if (sense == 0) {
1076 sense = rpmvercmp(aV, bV);
1077 if (sense == 0) {
1078 if (aR && *aR && bR && *bR) {
1079 sense = rpmvercmp(aR, bR);
1080 } else {
1081 /* always matches if the side with no release has SENSE_EQUAL */
1082 if ((aR && *aR && (BFlags & RPMSENSE_EQUAL)) ||
1083 (bR && *bR && (AFlags & RPMSENSE_EQUAL))) {
1084 aEVR = _free(aEVR)rfree((aEVR));
1085 bEVR = _free(bEVR)rfree((bEVR));
1086 result = 1;
1087 goto exit;
1088 }
1089 }
1090 }
1091 }
1092
1093 /* Detect overlap of {A,B} range. */
1094 if (sense < 0 && ((AFlags & RPMSENSE_GREATER) || (BFlags & RPMSENSE_LESS))) {
1095 result = 1;
1096 } else if (sense > 0 && ((AFlags & RPMSENSE_LESS) || (BFlags & RPMSENSE_GREATER))) {
1097 result = 1;
1098 } else if (sense == 0 &&
1099 (((AFlags & RPMSENSE_EQUAL) && (BFlags & RPMSENSE_EQUAL)) ||
1100 ((AFlags & RPMSENSE_LESS) && (BFlags & RPMSENSE_LESS)) ||
1101 ((AFlags & RPMSENSE_GREATER) && (BFlags & RPMSENSE_GREATER)))) {
1102 result = 1;
1103 }
1104
1105exit:
1106 free(aEVR);
1107 free(bEVR);
1108 return result;
1109}
1110
1111int rpmdsCompareIndex(rpmds A, int aix, rpmds B, int bix)
1112{
1113 const char *AEVR, *BEVR;
1114 rpmsenseFlags AFlags, BFlags;
1115 int result;
1116
1117 /* Different names don't overlap. */
1118 if (!rpmstrPoolStreq(A->pool, rpmdsNIdIndex(A, aix),
1119 B->pool, rpmdsNIdIndex(B, bix))) {
1120 result = 0;
1121 goto exit;
1122 }
1123
1124 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
1125 if (!(A->EVR && A->Flags && B->EVR && B->Flags)) {
1126 result = 1;
1127 goto exit;
1128 }
1129
1130 /* Same name. If either A or B is an existence test, always overlap. */
1131 AFlags = rpmdsFlagsIndex(A, aix);
1132 BFlags = rpmdsFlagsIndex(B, bix);
1133 if (!((AFlags & RPMSENSE_SENSEMASK15) && (BFlags & RPMSENSE_SENSEMASK15))) {
1134 result = 1;
1135 goto exit;
1136 }
1137
1138 AEVR = rpmdsEVRIndex(A, aix);
1139 BEVR = rpmdsEVRIndex(B, bix);
1140 if (!(AEVR && *AEVR && BEVR && *BEVR)) {
1141 /* If either EVR is non-existent or empty, always overlap. */
1142 result = 1;
1143 } else {
1144 /* Both AEVR and BEVR exist, compare [epoch:]version[-release]. */
1145 result = rpmdsCompareEVR(AEVR, AFlags, BEVR, BFlags, B->nopromote);
1146 }
1147
1148exit:
1149 return result;
1150}
1151
1152int rpmdsCompare(const rpmds A, const rpmds B)
1153{
1154 return rpmdsCompareIndex(A, A->i, B, B->i);
1155}
1156
1157int rpmdsMatches(rpmstrPool pool, Header h, int prix,
1158 rpmds req, int selfevr, int nopromote)
1159{
1160 rpmds provides;
1161 rpmTagVal tag = RPMTAG_PROVIDENAME;
1162 int result = 0;
1163
1164 /* Get provides information from header */
1165 if (selfevr)
1166 provides = rpmdsThisPool(pool, h, tag, RPMSENSE_EQUAL);
1167 else
1168 provides = rpmdsNewPool(pool, h, tag, 0);
1169
1170 rpmdsSetNoPromote(provides, nopromote);
1171
1172 /*
1173 * For a self-provide and indexed provide, we only need one comparison.
1174 * Otherwise loop through the provides until match or end.
1175 */
1176 if (prix >= 0 || selfevr) {
1177 if (prix >= 0)
1178 rpmdsSetIx(provides, prix);
1179 result = rpmdsCompare(provides, req);
1180 } else {
1181 provides = rpmdsInit(provides);
1182 while (rpmdsNext(provides) >= 0) {
1183 result = rpmdsCompare(provides, req);
1184 /* If this provide matches the require, we're done. */
1185 if (result)
1186 break;
1187 }
1188 }
1189
1190 rpmdsFree(provides);
1191 return result;
1192}
1193
1194int rpmdsMatchesDep (const Header h, int ix, const rpmds req, int nopromote)
1195{
1196 return rpmdsMatches(NULL((void*)0), h, ix, req, 0, nopromote);
1197}
1198
1199int rpmdsAnyMatchesDep (const Header h, const rpmds req, int nopromote)
1200{
1201 return rpmdsMatches(NULL((void*)0), h, -1, req, 0, nopromote);
1202}
1203
1204int rpmdsNVRMatchesDep(const Header h, const rpmds req, int nopromote)
1205{
1206 return rpmdsMatches(NULL((void*)0), h, -1, req, 1, nopromote);
1207}
1208
1209/**
1210 */
1211struct rpmlibProvides_s {
1212 const char * featureName;
1213 const char * featureEVR;
1214 rpmsenseFlags featureFlags;
1215 const char * featureDescription;
1216};
1217
1218static const struct rpmlibProvides_s rpmlibProvides[] = {
1219 { "rpmlib(VersionedDependencies)", "3.0.3-1",
1220 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1221 N_("PreReq:, Provides:, and Obsoletes: dependencies support versions.")"PreReq:, Provides:, and Obsoletes: dependencies support versions." },
1222 { "rpmlib(CompressedFileNames)", "3.0.4-1",
1223 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1224 N_("file name(s) stored as (dirName,baseName,dirIndex) tuple, not as path.")"file name(s) stored as (dirName,baseName,dirIndex) tuple, not as path."},
1225#if HAVE_BZLIB_H1
1226 { "rpmlib(PayloadIsBzip2)", "3.0.5-1",
1227 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1228 N_("package payload can be compressed using bzip2.")"package payload can be compressed using bzip2." },
1229#endif
1230#if HAVE_LZMA_H1
1231 { "rpmlib(PayloadIsXz)", "5.2-1",
1232 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1233 N_("package payload can be compressed using xz.")"package payload can be compressed using xz." },
1234 { "rpmlib(PayloadIsLzma)", "4.4.2-1",
1235 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1236 N_("package payload can be compressed using lzma.")"package payload can be compressed using lzma." },
1237#endif
1238 { "rpmlib(PayloadFilesHavePrefix)", "4.0-1",
1239 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1240 N_("package payload file(s) have \"./\" prefix.")"package payload file(s) have \"./\" prefix." },
1241 { "rpmlib(ExplicitPackageProvide)", "4.0-1",
1242 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
1243 N_("package name-version-release is not implicitly provided.")"package name-version-release is not implicitly provided." },
1244 { "rpmlib(HeaderLoadSortsTags)", "4.0.1-1",
1245 ( RPMSENSE_EQUAL),
1246 N_("header tags are always sorted after being loaded.")"header tags are always sorted after being loaded." },
1247 { "rpmlib(ScriptletInterpreterArgs)", "4.0.3-1",
1248 ( RPMSENSE_EQUAL),
1249 N_("the scriptlet interpreter can use arguments from header.")"the scriptlet interpreter can use arguments from header." },
1250 { "rpmlib(PartialHardlinkSets)", "4.0.4-1",
1251 ( RPMSENSE_EQUAL),
1252 N_("a hardlink file set may be installed without being complete.")"a hardlink file set may be installed without being complete." },
1253 { "rpmlib(ConcurrentAccess)", "4.1-1",
1254 ( RPMSENSE_EQUAL),
1255 N_("package scriptlets may access the rpm database while installing.")"package scriptlets may access the rpm database while installing." },
1256#ifdef WITH_LUA1
1257 { "rpmlib(BuiltinLuaScripts)", "4.2.2-1",
1258 ( RPMSENSE_EQUAL),
1259 N_("internal support for lua scripts.")"internal support for lua scripts." },
1260#endif
1261 { "rpmlib(FileDigests)", "4.6.0-1",
1262 ( RPMSENSE_EQUAL),
1263 N_("file digest algorithm is per package configurable")"file digest algorithm is per package configurable" },
1264#ifdef WITH_CAP
1265 { "rpmlib(FileCaps)", "4.6.1-1",
1266 ( RPMSENSE_EQUAL),
1267 N_("support for POSIX.1e file capabilities")"support for POSIX.1e file capabilities" },
1268#endif
1269 { "rpmlib(ScriptletExpansion)", "4.9.0-1",
1270 ( RPMSENSE_EQUAL),
1271 N_("package scriptlets can be expanded at install time.")"package scriptlets can be expanded at install time." },
1272 { "rpmlib(TildeInVersions)", "4.10.0-1",
1273 ( RPMSENSE_EQUAL),
1274 N_("dependency comparison supports versions with tilde.")"dependency comparison supports versions with tilde." },
1275 { "rpmlib(LargeFiles)", "4.12.0-1",
1276 ( RPMSENSE_EQUAL),
1277 N_("support files larger than 4GB")"support files larger than 4GB" },
1278 { "rpmlib(RichDependencies)", "4.12.0-1",
1279 ( RPMSENSE_EQUAL),
1280 N_("support for rich dependencies.")"support for rich dependencies." },
1281 { NULL((void*)0), NULL((void*)0), 0, NULL((void*)0) }
1282};
1283
1284
1285int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp)
1286{
1287 const struct rpmlibProvides_s * rltblp = tblp;
1288 const struct rpmlibProvides_s * rlp;
1289 int rc = 0;
1290
1291 if (rltblp == NULL((void*)0))
1292 rltblp = rpmlibProvides;
1293
1294 for (rlp = rltblp; rlp->featureName != NULL((void*)0) && rc >= 0; rlp++) {
1295 rpmds ds = rpmdsSinglePool(pool, RPMTAG_PROVIDENAME, rlp->featureName,
1296 rlp->featureEVR, rlp->featureFlags);
1297 rc = rpmdsMerge(dsp, ds);
1298 rpmdsFree(ds);
1299 }
1300 /* freeze the pool to save memory, but only if private pool */
1301 if (*dsp && (*dsp)->pool != pool)
1302 rpmstrPoolFreeze((*dsp)->pool, 0);
1303 return (rc < 0) ? -1 : 0;
1304}
1305
1306int rpmdsRpmlib(rpmds * dsp, const void * tblp)
1307{
1308 return rpmdsRpmlibPool(NULL((void*)0), dsp, tblp);
1309}
1310
1311rpmstrPool rpmdsPool(rpmds ds)
1312{
1313 return (ds != NULL((void*)0)) ? ds->pool : NULL((void*)0);
1314}
1315
1316rpmsenseFlags rpmSanitizeDSFlags(rpmTagVal tagN, rpmsenseFlags Flags)
1317{
1318 rpmsenseFlags extra = RPMSENSE_ANY;
1319 switch (tagN) {
1320 case RPMTAG_PROVIDENAME:
1321 extra = Flags & RPMSENSE_FIND_PROVIDES;
1322 break;
1323 case RPMTAG_TRIGGERNAME:
1324 case RPMTAG_FILETRIGGERNAME:
1325 case RPMTAG_TRANSFILETRIGGERNAME:
1326 extra = Flags & RPMSENSE_TRIGGER(RPMSENSE_TRIGGERPREIN | RPMSENSE_TRIGGERIN | RPMSENSE_TRIGGERUN
| RPMSENSE_TRIGGERPOSTUN)
;
1327 break;
1328 case RPMTAG_RECOMMENDNAME:
1329 case RPMTAG_SUGGESTNAME:
1330 case RPMTAG_SUPPLEMENTNAME:
1331 case RPMTAG_ENHANCENAME:
1332 case RPMTAG_REQUIRENAME:
1333 extra = Flags & (_ALL_REQUIRES_MASK( RPMSENSE_INTERP | RPMSENSE_SCRIPT_PRE | RPMSENSE_SCRIPT_POST
| RPMSENSE_SCRIPT_PREUN | RPMSENSE_SCRIPT_POSTUN | RPMSENSE_SCRIPT_VERIFY
| RPMSENSE_FIND_REQUIRES | RPMSENSE_RPMLIB | RPMSENSE_KEYRING
| RPMSENSE_PRETRANS | RPMSENSE_POSTTRANS | RPMSENSE_PREREQ |
RPMSENSE_MISSINGOK)
);
1334 break;
1335 case RPMTAG_CONFLICTNAME:
1336 extra = Flags;
1337 break;
1338 default:
1339 break;
1340 }
1341 return (Flags & RPMSENSE_SENSEMASK15) | extra;
1342}
1343
1344static struct ReqComp {
1345const char * token;
1346 rpmsenseFlags sense;
1347} const ReqComparisons[] = {
1348 { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
1349 { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
1350 { "<", RPMSENSE_LESS},
1351
1352 { "==", RPMSENSE_EQUAL},
1353 { "=", RPMSENSE_EQUAL},
1354
1355 { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
1356 { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
1357 { ">", RPMSENSE_GREATER},
1358
1359 { NULL((void*)0), 0 },
1360};
1361
1362rpmsenseFlags rpmParseDSFlags(const char *str, size_t len)
1363{
1364 const struct ReqComp *rc;
1365 for (rc = ReqComparisons; rc->token != NULL((void*)0); rc++)
1366 if (len == strlen(rc->token) && rstreqn(str, rc->token, len))
1367 return rc->sense;
1368 return 0;
1369}
1370
1371static struct RichOpComp {
1372 const char * token;
1373 rpmrichOp op;
1374} const RichOps[] = {
1375 { "and", RPMRICHOP_AND},
1376 { "or", RPMRICHOP_OR},
1377 { "if", RPMRICHOP_IF},
1378 { "else", RPMRICHOP_ELSE},
1379 { NULL((void*)0), 0 },
1380};
1381
1382int rpmdsIsRich(rpmds dep)
1383{
1384 const char * n = rpmdsN(dep);
1385 return (n && n[0] == '(');
1386}
1387
1388static rpmRC parseRichDepOp(const char **dstrp, rpmrichOp *opp, char **emsg)
1389{
1390 const char *p = *dstrp, *pe = p;
1391 const struct RichOpComp *ro;
1392
1393 while (*pe && !risspace(*pe) && *pe != ')')
1394 pe++;
1395 for (ro = RichOps; ro->token != NULL((void*)0); ro++)
1396 if (pe - p == strlen(ro->token) && rstreqn(p, ro->token, pe - p)) {
1397 *opp = ro->op;
1398 *dstrp = pe;
1399 return RPMRC_OK;
1400 }
1401 if (emsg)
1402 rasprintf(emsg, _("Unknown rich dependency op '%.*s'")dcgettext ("rpm", "Unknown rich dependency op '%.*s'", 5), (int)(pe - p), p);
1403 return RPMRC_FAIL;
1404}
1405
1406const char *rpmrichOpStr(rpmrichOp op)
1407{
1408 if (op == RPMRICHOP_SINGLE)
1409 return "SINGLE";
1410 if (op == RPMRICHOP_AND)
1411 return "and";
1412 if (op == RPMRICHOP_OR)
1413 return "or";
1414 if (op == RPMRICHOP_IF)
1415 return "if";
1416 if (op == RPMRICHOP_ELSE)
1417 return "else";
1418 return NULL((void*)0);
1419}
1420
1421
1422#define SKIPWHITE(_x){while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x
)++;}
{while (*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
1423#define SKIPNONWHITEX(_x){int bl = 0; while (*(_x) &&!(risspace(*_x) || *(_x) ==
',' || (*(_x) == ')' && bl-- <= 0))) if (*(_x)++ ==
'(') bl++;}
{int bl = 0; while (*(_x) &&!(risspace(*_x) || *(_x) == ',' || (*(_x) == ')' && bl-- <= 0))) if (*(_x)++ == '(') bl++;}
1424
1425static rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
1426{
1427 const char *p = *dstrp;
1428 const char *n, *e = 0;
1429 int nl, el = 0;
1430 rpmsenseFlags sense = 0;
1431
1432 n = p;
1433 SKIPNONWHITEX(p){int bl = 0; while (*(p) &&!(risspace(*p) || *(p) == ','
|| (*(p) == ')' && bl-- <= 0))) if (*(p)++ == '('
) bl++;}
;
1434 nl = p - n;
1435 if (nl == 0) {
1436 if (emsg)
1437 rasprintf(emsg, _("Name required")dcgettext ("rpm", "Name required", 5));
1438 return RPMRC_FAIL;
1439 }
1440 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
1441 if (*p) {
1442 const char *pe = p;
1443
1444 SKIPNONWHITEX(pe){int bl = 0; while (*(pe) &&!(risspace(*pe) || *(pe) ==
',' || (*(pe) == ')' && bl-- <= 0))) if (*(pe)++ ==
'(') bl++;}
;
1445 sense = rpmParseDSFlags(p, pe - p);
1446 if (sense) {
1447 p = pe;
1448 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
1449 e = p;
1450 SKIPNONWHITEX(p){int bl = 0; while (*(p) &&!(risspace(*p) || *(p) == ','
|| (*(p) == ')' && bl-- <= 0))) if (*(p)++ == '('
) bl++;}
;
1451 el = p - e;
1452 }
1453 }
1454 if (e && el == 0) {
1455 if (emsg)
1456 rasprintf(emsg, _("Version required")dcgettext ("rpm", "Version required", 5));
1457 return RPMRC_FAIL;
1458 }
1459 if (cb(cbdata, RPMRICH_PARSE_SIMPLE, n, nl, e, el, sense, RPMRICHOP_SINGLE, emsg) != RPMRC_OK)
1460 return RPMRC_FAIL;
1461 *dstrp = p;
1462 return RPMRC_OK;
1463}
1464
1465rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
1466{
1467 const char *p = *dstrp, *pe;
1468 rpmrichOp op = RPMRICHOP_SINGLE, chainop = 0;
1469
1470 if (cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK)
1471 return RPMRC_FAIL;
1472 if (*p++ != '(') {
1473 if (emsg)
1474 rasprintf(emsg, _("Rich dependency does not start with '('")dcgettext ("rpm", "Rich dependency does not start with '('", 5
)
);
1475 return RPMRC_FAIL;
1476 }
1477 for (;;) {
1478 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
1479 if (*p == ')') {
1480 if (emsg) {
1481 if (chainop)
1482 rasprintf(emsg, _("Missing argument to rich dependency op")dcgettext ("rpm", "Missing argument to rich dependency op", 5
)
);
1483 else
1484 rasprintf(emsg, _("Empty rich dependency")dcgettext ("rpm", "Empty rich dependency", 5));
1485 }
1486 return RPMRC_FAIL;
1487 }
1488 if (*p == '(') {
1489 if (rpmrichParse(&p, emsg, cb, cbdata) != RPMRC_OK)
1490 return RPMRC_FAIL;
1491 } else {
1492 if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK)
1493 return RPMRC_FAIL;
1494 }
1495 SKIPWHITE(p){while (*(p) && (risspace(*p) || *(p) == ',')) (p)++;
}
;
1496 if (!*p) {
1497 if (emsg)
1498 rasprintf(emsg, _("Unterminated rich dependency: %s")dcgettext ("rpm", "Unterminated rich dependency: %s", 5), *dstrp);
1499 return RPMRC_FAIL;
1500 }
1501 if (*p == ')')
1502 break;
1503 pe = p;
1504 if (parseRichDepOp(&pe, &op, emsg) != RPMRC_OK)
1505 return RPMRC_FAIL;
1506 if (op == RPMRICHOP_ELSE && chainop == RPMRICHOP_IF)
1507 chainop = 0;
1508 if (chainop && op != chainop) {
1509 if (emsg)
1510 rasprintf(emsg, _("Cannot chain different ops")dcgettext ("rpm", "Cannot chain different ops", 5));
1511 return RPMRC_FAIL;
1512 }
1513 if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR) {
1514 if (emsg)
1515 rasprintf(emsg, _("Can only chain AND and OR ops")dcgettext ("rpm", "Can only chain AND and OR ops", 5));
1516 return RPMRC_FAIL;
1517 }
1518 if (cb(cbdata, RPMRICH_PARSE_OP, p, pe - p, 0, 0, 0, op, emsg) != RPMRC_OK)
1519 return RPMRC_FAIL;
1520 chainop = op;
1521 p = pe;
1522 }
1523 p++;
1524 if (cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK)
1525 return RPMRC_FAIL;
1526 *dstrp = p;
1527 return RPMRC_OK;
1528}
1529
1530
1531struct rpmdsParseRichDepData {
1532 rpmds dep;
1533 rpmsenseFlags depflags;
1534
1535 rpmds leftds;
1536 rpmds rightds;
1537 rpmrichOp op;
1538
1539 int depth;
1540 const char *rightstart;
1541 int dochain;
1542};
1543
1544static rpmRC rpmdsParseRichDepCB(void *cbdata, rpmrichParseType type,
1545 const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
1546 rpmrichOp op, char **emsg) {
1547 struct rpmdsParseRichDepData *data = cbdata;
1548 rpmds ds = 0;
1549
1550 if (type == RPMRICH_PARSE_ENTER)
1551 data->depth++;
1552 else if (type == RPMRICH_PARSE_LEAVE) {
1553 if (--data->depth == 0 && data->dochain && data->rightstart) {
1554 /* chain op hack, construct a sub-ds from the right side of the chain */
1555 char *right = xmalloc(n + nl - data->rightstart + 2)rmalloc((n + nl - data->rightstart + 2));
1556 right[0] = '(';
1557 strncpy(right + 1, data->rightstart, n + nl - data->rightstart);
1558 right[n + nl - data->rightstart + 1] = 0;
1559 data->rightds = rpmdsFree(data->rightds);
1560 ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, data->depflags, 0, 0, 0);
1561 ds->N[0] = rpmstrPoolId(ds->pool, right, 1);
1562 ds->EVR[0] = rpmstrPoolId(ds->pool, "", 1);
1563 data->rightds = ds;
1564 free(right);
1565 }
1566 }
1567 if (data->depth != 1)
1568 return RPMRC_OK; /* we're only interested in top-level parsing */
1569 if ((type == RPMRICH_PARSE_SIMPLE || type == RPMRICH_PARSE_LEAVE) && !data->dochain) {
1570 if (type == RPMRICH_PARSE_SIMPLE && data->dep->tagN == RPMTAG_REQUIRENAME && nl > 7 &&
1571 rstreqn(n, "rpmlib(", sizeof("rpmlib(")-1))
1572 sense |= RPMSENSE_RPMLIB;
1573 ds = singleDS(data->dep->pool, data->dep->tagN, 0, 0, sense | data->depflags, 0, 0, 0);
1574 ds->N[0] = rpmstrPoolIdn(ds->pool, n, nl, 1);
1575 ds->EVR[0] = rpmstrPoolIdn(ds->pool, e ? e : "", el, 1);
1576 if (!data->leftds)
1577 data->leftds = ds;
1578 else {
1579 data->rightds = ds;
1580 data->rightstart = n;
1581 }
1582 }
1583 if (type == RPMRICH_PARSE_OP) {
1584 if (data->op != RPMRICHOP_SINGLE)
1585 data->dochain = 1; /* this is a chained op */
1586 else
1587 data->op = op;
1588 }
1589 return RPMRC_OK;
1590}
1591
1592
1593rpmRC rpmdsParseRichDep(rpmds dep, rpmds *leftds, rpmds *rightds, rpmrichOp *op, char **emsg)
1594{
1595 rpmRC rc;
1596 struct rpmdsParseRichDepData data;
1597 const char *depstr = rpmdsN(dep);
1598 memset(&data, 0, sizeof(data));
1599 data.dep = dep;
1600 data.op = RPMRICHOP_SINGLE;
1601 data.depflags = rpmdsFlags(dep) & ~(RPMSENSE_SENSEMASK15 | RPMSENSE_MISSINGOK);
1602 rc = rpmrichParse(&depstr, emsg, rpmdsParseRichDepCB, &data);
1603 if (rc == RPMRC_OK && *depstr) {
1604 if (emsg)
1605 rasprintf(emsg, _("Junk after rich dependency")dcgettext ("rpm", "Junk after rich dependency", 5));
1606 rc = RPMRC_FAIL;
1607 }
1608 if (rc != RPMRC_OK) {
1609 rpmdsFree(data.leftds);
1610 rpmdsFree(data.rightds);
1611 } else {
1612 *leftds = data.leftds;
1613 *rightds = data.rightds;
1614 *op = data.op;
1615 }
1616 return rc;
1617}
1618