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