6 #include <rpm/rpmtypes.h>
7 #include <rpm/rpmlib.h> /* rpmvercmp */
8 #include <rpm/rpmstring.h>
9 #include <rpm/rpmlog.h>
10 #include <rpm/rpmds.h>
16 int _rpmds_nopromote = 1;
19 * A package dependency set.
22 const char * Type; /*!< Tag name. */
23 char * DNEVR; /*!< Formatted dependency string. */
24 const char ** N; /*!< Name. */
25 const char ** EVR; /*!< Epoch-Version-Release. */
26 rpmsenseFlags * Flags; /*!< Bit(s) identifying context/comparison. */
27 rpm_color_t * Color; /*!< Bit(s) calculated from file color(s). */
28 int32_t * Refs; /*!< No. of file refs. */
29 time_t BT; /*!< Package build time tie breaker. */
30 rpmTag tagN; /*!< Header tag. */
31 int32_t Count; /*!< No. of elements */
32 int i; /*!< Element index. */
33 unsigned l; /*!< Low element (bsearch). */
34 unsigned u; /*!< High element (bsearch). */
35 int nopromote; /*!< Don't promote Epoch: in rpmdsCompare()? */
36 int nrefs; /*!< Reference count. */
39 static const char ** rpmdsDupArgv(const char ** argv, int argc);
41 static int dsType(rpmTag tag,
42 const char ** Type, rpmTag * tagEVR, rpmTag * tagF)
46 rpmTag evr = RPMTAG_NOT_FOUND;
47 rpmTag f = RPMTAG_NOT_FOUND;
49 if (tag == RPMTAG_PROVIDENAME) {
51 evr = RPMTAG_PROVIDEVERSION;
52 f = RPMTAG_PROVIDEFLAGS;
53 } else if (tag == RPMTAG_REQUIRENAME) {
55 evr = RPMTAG_REQUIREVERSION;
56 f = RPMTAG_REQUIREFLAGS;
57 } else if (tag == RPMTAG_CONFLICTNAME) {
59 evr = RPMTAG_CONFLICTVERSION;
60 f = RPMTAG_CONFLICTFLAGS;
61 } else if (tag == RPMTAG_OBSOLETENAME) {
63 evr = RPMTAG_OBSOLETEVERSION;
64 f = RPMTAG_OBSOLETEFLAGS;
65 } else if (tag == RPMTAG_TRIGGERNAME) {
67 evr = RPMTAG_TRIGGERVERSION;
68 f = RPMTAG_TRIGGERFLAGS;
73 if (tagEVR) *tagEVR = evr;
78 rpmds rpmdsUnlink(rpmds ds, const char * msg)
80 if (ds == NULL) return NULL;
81 if (_rpmds_debug && msg != NULL)
82 fprintf(stderr, "--> ds %p -- %d %s\n", ds, ds->nrefs, msg);
87 rpmds rpmdsLink(rpmds ds, const char * msg)
89 if (ds == NULL) return NULL;
92 if (_rpmds_debug && msg != NULL)
93 fprintf(stderr, "--> ds %p ++ %d %s\n", ds, ds->nrefs, msg);
98 rpmds rpmdsFree(rpmds ds)
106 return rpmdsUnlink(ds, ds->Type);
108 if (_rpmds_debug < 0)
109 fprintf(stderr, "*** ds %p\t%s[%d]\n", ds, ds->Type, ds->Count);
111 if (dsType(ds->tagN, NULL, &tagEVR, &tagF))
115 ds->N = _free(ds->N);
116 ds->EVR = _free(ds->EVR);
117 ds->Flags = _free(ds->Flags);
120 ds->DNEVR = _free(ds->DNEVR);
121 ds->Color = _free(ds->Color);
122 ds->Refs = _free(ds->Refs);
124 (void) rpmdsUnlink(ds, ds->Type);
125 memset(ds, 0, sizeof(*ds)); /* XXX trash and burn */
130 rpmds rpmdsNew(Header h, rpmTag tagN, int flags)
135 struct rpmtd_s names;
136 headerGetFlags hgflags = HEADERGET_ALLOC|HEADERGET_ARGV;
138 if (dsType(tagN, &Type, &tagEVR, &tagF))
141 if (headerGet(h, tagN, &names, hgflags) && rpmtdCount(&names) > 0) {
142 struct rpmtd_s evr, flags, buildtime;
145 ds = xcalloc(1, sizeof(*ds));
151 ds->Count = rpmtdCount(&names);
152 ds->nopromote = _rpmds_nopromote;
154 headerGet(h, tagEVR, &evr, hgflags);
156 headerGet(h, tagF, &flags, hgflags);
157 ds->Flags = flags.data;
159 headerGet(h, RPMTAG_BUILDTIME, &buildtime, HEADERGET_MINMEM);
160 BTp = rpmtdGetUint32(&buildtime);
161 ds->BT = BTp ? *BTp : 0;
162 rpmtdFreeData(&buildtime);
163 ds->Color = xcalloc(ds->Count, sizeof(*ds->Color));
164 ds->Refs = xcalloc(ds->Count, sizeof(*ds->Refs));
165 ds = rpmdsLink(ds, ds->Type);
167 if (_rpmds_debug < 0)
168 fprintf(stderr, "*** ds %p\t%s[%d]\n", ds, ds->Type, ds->Count);
175 char * rpmdsNewDNEVR(const char * dspfx, const rpmds ds)
181 if (dspfx) nb += strlen(dspfx) + 1;
182 if (ds->N[ds->i]) nb += strlen(ds->N[ds->i]);
183 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
184 if (ds->Flags != NULL && (ds->Flags[ds->i] & RPMSENSE_SENSEMASK)) {
186 if (ds->Flags[ds->i] & RPMSENSE_LESS) nb++;
187 if (ds->Flags[ds->i] & RPMSENSE_GREATER) nb++;
188 if (ds->Flags[ds->i] & RPMSENSE_EQUAL) nb++;
190 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
191 if (ds->EVR != NULL && ds->EVR[ds->i] && *ds->EVR[ds->i]) {
193 nb += strlen(ds->EVR[ds->i]);
196 t = tbuf = xmalloc(nb + 1);
198 t = stpcpy(t, dspfx);
202 t = stpcpy(t, ds->N[ds->i]);
203 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
204 if (ds->Flags != NULL && (ds->Flags[ds->i] & RPMSENSE_SENSEMASK)) {
205 if (t != tbuf) *t++ = ' ';
206 if (ds->Flags[ds->i] & RPMSENSE_LESS) *t++ = '<';
207 if (ds->Flags[ds->i] & RPMSENSE_GREATER) *t++ = '>';
208 if (ds->Flags[ds->i] & RPMSENSE_EQUAL) *t++ = '=';
210 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
211 if (ds->EVR != NULL && ds->EVR[ds->i] && *ds->EVR[ds->i]) {
212 if (t != tbuf) *t++ = ' ';
213 t = stpcpy(t, ds->EVR[ds->i]);
219 rpmds rpmdsThis(Header h, rpmTag tagN, rpmsenseFlags Flags)
225 evr = headerGetEVR(h, &n);
226 ds = rpmdsSingle(tagN, n, evr, Flags);
231 rpmds rpmdsSingle(rpmTag tagN, const char * N, const char * EVR, rpmsenseFlags Flags)
236 if (dsType(tagN, &Type, NULL, NULL))
239 ds = xcalloc(1, sizeof(*ds));
242 { time_t now = time(NULL);
246 ds->nopromote = _rpmds_nopromote;
248 ds->N = rpmdsDupArgv(&N, 1);
249 ds->EVR = rpmdsDupArgv(&EVR, 1);
251 ds->Flags = xmalloc(sizeof(*ds->Flags));
252 ds->Flags[0] = Flags;
256 return rpmdsLink(ds, (ds ? ds->Type : NULL));
259 int rpmdsCount(const rpmds ds)
261 return (ds != NULL ? ds->Count : 0);
264 int rpmdsIx(const rpmds ds)
266 return (ds != NULL ? ds->i : -1);
269 int rpmdsSetIx(rpmds ds, int ix)
276 ds->DNEVR = _free(ds->DNEVR);
281 const char * rpmdsDNEVR(const rpmds ds)
283 const char * DNEVR = NULL;
285 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
286 if (ds->DNEVR == NULL) {
287 char t[2] = { ds->Type[0], '\0' };
288 ds->DNEVR = rpmdsNewDNEVR(t, ds);
295 const char * rpmdsN(const rpmds ds)
297 const char * N = NULL;
299 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
306 const char * rpmdsEVR(const rpmds ds)
308 const char * EVR = NULL;
310 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
312 EVR = ds->EVR[ds->i];
317 rpmsenseFlags rpmdsFlags(const rpmds ds)
319 rpmsenseFlags Flags = 0;
321 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
322 if (ds->Flags != NULL)
323 Flags = ds->Flags[ds->i];
328 rpmTag rpmdsTagN(const rpmds ds)
337 time_t rpmdsBT(const rpmds ds)
340 if (ds != NULL && ds->BT > 0)
345 time_t rpmdsSetBT(const rpmds ds, time_t BT)
355 int rpmdsNoPromote(const rpmds ds)
360 nopromote = ds->nopromote;
364 int rpmdsSetNoPromote(rpmds ds, int nopromote)
369 onopromote = ds->nopromote;
370 ds->nopromote = nopromote;
375 rpm_color_t rpmdsColor(const rpmds ds)
377 rpm_color_t Color = 0;
379 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
380 if (ds->Color != NULL)
381 Color = ds->Color[ds->i];
386 rpm_color_t rpmdsSetColor(const rpmds ds, rpm_color_t color)
388 rpm_color_t ocolor = 0;
390 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
391 if (ds->Color != NULL) {
392 ocolor = ds->Color[ds->i];
393 ds->Color[ds->i] = color;
399 int32_t rpmdsRefs(const rpmds ds)
403 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
404 if (ds->Refs != NULL)
405 Refs = ds->Refs[ds->i];
410 int32_t rpmdsSetRefs(const rpmds ds, int32_t refs)
414 if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
415 if (ds->Refs != NULL) {
416 orefs = ds->Refs[ds->i];
417 ds->Refs[ds->i] = refs;
423 void rpmdsNotify(rpmds ds, const char * where, int rc)
429 if (!(ds != NULL && ds->i >= 0 && ds->i < ds->Count))
431 if (!(ds->Type != NULL && (DNEVR = rpmdsDNEVR(ds)) != NULL))
434 rpmlog(RPMLOG_DEBUG, "%9s: %-45s %-s %s\n", ds->Type,
435 (rstreq(DNEVR, "cached") ? DNEVR : DNEVR+2),
436 (rc ? _("NO ") : _("YES")),
437 (where != NULL ? where : ""));
440 int rpmdsNext(rpmds ds)
444 if (ds != NULL && ++ds->i >= 0) {
445 if (ds->i < ds->Count) {
447 ds->DNEVR = _free(ds->DNEVR);
451 if (_rpmds_debug < 0 && i != -1)
452 fprintf(stderr, "*** ds %p\t%s[%d]: %s\n", ds, (ds->Type ? ds->Type : "?Type?"), i, (ds->DNEVR ? ds->DNEVR : "?DNEVR?"));
459 rpmds rpmdsInit(rpmds ds)
463 ds->DNEVR = _free(ds->DNEVR);
469 const char ** rpmdsDupArgv(const char ** argv, int argc)
478 for (ac = 0; ac < argc && argv[ac]; ac++) {
479 nb += strlen(argv[ac]) + 1;
481 nb += (ac + 1) * sizeof(*av);
484 t = (char *) (av + ac + 1);
485 for (ac = 0; ac < argc && argv[ac]; ac++) {
487 t = stpcpy(t, argv[ac]) + 1;
493 static rpmds rpmdsDup(const rpmds ods)
495 rpmds ds = xcalloc(1, sizeof(*ds));
498 ds->Type = ods->Type;
499 ds->tagN = ods->tagN;
500 ds->Count = ods->Count;
504 ds->nopromote = ods->nopromote;
506 nb = (ds->Count+1) * sizeof(*ds->N);
507 ds->N = rpmdsDupArgv(ods->N, ods->Count);
509 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
510 assert(ods->EVR != NULL);
511 assert(ods->Flags != NULL);
513 nb = (ds->Count+1) * sizeof(*ds->EVR);
514 ds->EVR = rpmdsDupArgv(ods->EVR, ods->Count);
516 nb = (ds->Count * sizeof(*ds->Flags));
517 ds->Flags = memcpy(xmalloc(nb), ods->Flags, nb);
519 /* FIX: ds->Flags is kept, not only */
520 return rpmdsLink(ds, (ds ? ds->Type : NULL));
524 int rpmdsFind(rpmds ds, const rpmds ods)
528 if (ds == NULL || ods == NULL)
533 while (ds->l < ds->u) {
534 ds->i = (ds->l + ds->u) / 2;
536 comparison = strcmp(ods->N[ods->i], ds->N[ds->i]);
538 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
539 if (comparison == 0 && ods->EVR && ds->EVR)
540 comparison = strcmp(ods->EVR[ods->i], ds->EVR[ds->i]);
541 if (comparison == 0 && ods->Flags && ds->Flags)
542 comparison = (ods->Flags[ods->i] - ds->Flags[ds->i]);
546 else if (comparison > 0)
554 int rpmdsMerge(rpmds * dsp, rpmds ods)
559 rpmsenseFlags * Flags;
563 if (dsp == NULL || ods == NULL)
566 /* If not initialized yet, dup the 1st entry. */
570 *dsp = rpmdsDup(ods);
581 ods = rpmdsInit(ods);
583 while (rpmdsNext(ods) >= 0) {
585 * If this entry is already present, don't bother.
587 if (rpmdsFind(ds, ods) >= 0)
593 for (j = ds->Count; j > ds->u; j--)
594 ds->N[j] = ds->N[j-1];
595 ds->N[ds->u] = ods->N[ods->i];
596 N = rpmdsDupArgv(ds->N, ds->Count+1);
597 ds->N = _free(ds->N);
600 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
601 assert(ods->EVR != NULL);
602 assert(ods->Flags != NULL);
604 for (j = ds->Count; j > ds->u; j--)
605 ds->EVR[j] = ds->EVR[j-1];
606 ds->EVR[ds->u] = ods->EVR[ods->i];
607 EVR = rpmdsDupArgv(ds->EVR, ds->Count+1);
608 ds->EVR = _free(ds->EVR);
611 Flags = xmalloc((ds->Count+1) * sizeof(*Flags));
613 memcpy(Flags, ds->Flags, ds->u * sizeof(*Flags));
614 if (ds->u < ds->Count)
615 memcpy(Flags + ds->u + 1, ds->Flags + ds->u,
616 (ds->Count - ds->u) * sizeof(*Flags));
617 Flags[ds->u] = ods->Flags[ods->i];
618 ds->Flags = _free(ds->Flags);
630 int rpmdsSearch(rpmds ds, rpmds ods)
635 if (ds == NULL || ods == NULL)
638 /* Binary search to find the [l,u) subset that contains N */
645 comparison = strcmp(ods->N[ods->i], ds->N[i]);
649 else if (comparison > 0)
652 /* Set l to 1st member of set that contains N. */
653 if (!rstreq(ods->N[ods->i], ds->N[l]))
655 while (l > 0 && rstreq(ods->N[ods->i], ds->N[l-1]))
657 /* Set u to 1st member of set that does not contain N. */
658 if (u >= ds->Count || !rstreq(ods->N[ods->i], ds->N[u]))
660 while (++u < ds->Count) {
661 if (!rstreq(ods->N[ods->i], ds->N[u]))
662 /*@innerbreak@*/ break;
668 /* Check each member of [l,u) subset for ranges overlap. */
671 int save = rpmdsSetIx(ds, l-1);
672 while ((l = rpmdsNext(ds)) >= 0 && (l < u)) {
673 if ((i = rpmdsCompare(ods, ds)) != 0)
676 /* Return element index that overlaps, or -1. */
680 (void) rpmdsSetIx(ds, save);
687 * Split EVR into epoch, version, and release components.
688 * @param evr [epoch:]version[-release] string
689 * @retval *ep pointer to epoch
690 * @retval *vp pointer to version
691 * @retval *rp pointer to release
694 void parseEVR(char * evr,
700 const char *version; /* assume only version is present */
705 while (*s && risdigit(*s)) s++; /* s points to epoch terminator */
706 se = strrchr(s, '-'); /* se points to version terminator */
712 if (*epoch == '\0') epoch = "0";
714 epoch = NULL; /* XXX disable epoch compare if missing */
725 if (vp) *vp = version;
726 if (rp) *rp = release;
729 int rpmdsCompare(const rpmds A, const rpmds B)
732 const char *aE, *aV, *aR, *bE, *bV, *bR;
736 /* Different names don't overlap. */
737 if (!rstreq(A->N[A->i], B->N[B->i])) {
742 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
743 if (!(A->EVR && A->Flags && B->EVR && B->Flags)) {
748 /* Same name. If either A or B is an existence test, always overlap. */
749 if (!((A->Flags[A->i] & RPMSENSE_SENSEMASK) && (B->Flags[B->i] & RPMSENSE_SENSEMASK))) {
754 /* If either EVR is non-existent or empty, always overlap. */
755 if (!(A->EVR[A->i] && *A->EVR[A->i] && B->EVR[B->i] && *B->EVR[B->i])) {
760 /* Both AEVR and BEVR exist. */
761 aEVR = xstrdup(A->EVR[A->i]);
762 parseEVR(aEVR, &aE, &aV, &aR);
763 bEVR = xstrdup(B->EVR[B->i]);
764 parseEVR(bEVR, &bE, &bV, &bR);
766 /* Compare {A,B} [epoch:]version[-release] */
768 if (aE && *aE && bE && *bE)
769 sense = rpmvercmp(aE, bE);
770 else if (aE && *aE && atol(aE) > 0) {
775 } else if (bE && *bE && atol(bE) > 0)
779 sense = rpmvercmp(aV, bV);
780 if (sense == 0 && aR && *aR && bR && *bR)
781 sense = rpmvercmp(aR, bR);
786 /* Detect overlap of {A,B} range. */
788 if (sense < 0 && ((A->Flags[A->i] & RPMSENSE_GREATER) || (B->Flags[B->i] & RPMSENSE_LESS))) {
790 } else if (sense > 0 && ((A->Flags[A->i] & RPMSENSE_LESS) || (B->Flags[B->i] & RPMSENSE_GREATER))) {
792 } else if (sense == 0 &&
793 (((A->Flags[A->i] & RPMSENSE_EQUAL) && (B->Flags[B->i] & RPMSENSE_EQUAL)) ||
794 ((A->Flags[A->i] & RPMSENSE_LESS) && (B->Flags[B->i] & RPMSENSE_LESS)) ||
795 ((A->Flags[A->i] & RPMSENSE_GREATER) && (B->Flags[B->i] & RPMSENSE_GREATER)))) {
803 void rpmdsProblem(rpmps ps, const char * pkgNEVR, const rpmds ds,
804 const fnpyKey * suggestedKeys, int adding)
806 const char * Name = rpmdsN(ds);
807 const char * DNEVR = rpmdsDNEVR(ds);
808 const char * EVR = rpmdsEVR(ds);
812 if (ps == NULL) return;
814 if (Name == NULL) Name = "?N?";
815 if (EVR == NULL) EVR = "?EVR?";
816 if (DNEVR == NULL) DNEVR = "? ?N? ?OP? ?EVR?";
818 rpmlog(RPMLOG_DEBUG, "package %s has unsatisfied %s: %s\n",
819 pkgNEVR, ds->Type, DNEVR+2);
821 switch ((unsigned)DNEVR[0]) {
822 case 'C': type = RPMPROB_CONFLICT; break;
824 case 'R': type = RPMPROB_REQUIRES; break;
827 key = (suggestedKeys ? suggestedKeys[0] : NULL);
828 rpmpsAppend(ps, type, pkgNEVR, key, NULL, NULL, DNEVR, adding);
831 int rpmdsAnyMatchesDep (const Header h, const rpmds req, int nopromote)
833 rpmds provides = NULL;
836 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
837 if (req->EVR == NULL || req->Flags == NULL)
840 if (!(req->Flags[req->i] & RPMSENSE_SENSEMASK) || !req->EVR[req->i] || *req->EVR[req->i] == '\0')
843 /* Get provides information from header */
844 provides = rpmdsInit(rpmdsNew(h, RPMTAG_PROVIDENAME, 0));
845 if (provides == NULL)
846 goto exit; /* XXX should never happen */
848 (void) rpmdsSetNoPromote(provides, nopromote);
851 * Rpm prior to 3.0.3 did not have versioned provides.
852 * If no provides version info is available, match any/all requires
855 if (provides->EVR == NULL) {
861 if (provides != NULL)
862 while (rpmdsNext(provides) >= 0) {
864 /* Filter out provides that came along for the ride. */
865 if (!rstreq(provides->N[provides->i], req->N[req->i]))
868 result = rpmdsCompare(provides, req);
870 /* If this provide matches the require, we're done. */
876 provides = rpmdsFree(provides);
881 int rpmdsNVRMatchesDep(const Header h, const rpmds req, int nopromote)
885 rpmsenseFlags pkgFlags = RPMSENSE_EQUAL;
887 int rc = 1; /* XXX assume match, names already match here */
889 /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
890 if (req->EVR == NULL || req->Flags == NULL)
893 if (!((req->Flags[req->i] & RPMSENSE_SENSEMASK) && req->EVR[req->i] && *req->EVR[req->i]))
896 /* Get package information from header */
897 pkgEVR = headerGetEVR(h, &pkgN);
898 if ((pkg = rpmdsSingle(RPMTAG_PROVIDENAME, pkgN, pkgEVR, pkgFlags)) != NULL) {
900 (void) rpmdsSetNoPromote(pkg, nopromote);
901 rc = rpmdsCompare(pkg, req);
902 pkg = rpmdsFree(pkg);
911 struct rpmlibProvides_s {
912 const char * featureName;
913 const char * featureEVR;
914 rpmsenseFlags featureFlags;
915 const char * featureDescription;
918 static const struct rpmlibProvides_s rpmlibProvides[] = {
919 { "rpmlib(VersionedDependencies)", "3.0.3-1",
920 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
921 N_("PreReq:, Provides:, and Obsoletes: dependencies support versions.") },
922 { "rpmlib(CompressedFileNames)", "3.0.4-1",
923 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
924 N_("file name(s) stored as (dirName,baseName,dirIndex) tuple, not as path.")},
926 { "rpmlib(PayloadIsBzip2)", "3.0.5-1",
927 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
928 N_("package payload can be compressed using bzip2.") },
931 { "rpmlib(PayloadIsXz)", "5.2-1",
932 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
933 N_("package payload can be compressed using xz.") },
934 { "rpmlib(PayloadIsLzma)", "4.4.2-1",
935 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
936 N_("package payload can be compressed using lzma.") },
938 { "rpmlib(PayloadFilesHavePrefix)", "4.0-1",
939 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
940 N_("package payload file(s) have \"./\" prefix.") },
941 { "rpmlib(ExplicitPackageProvide)", "4.0-1",
942 (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
943 N_("package name-version-release is not implicitly provided.") },
944 { "rpmlib(HeaderLoadSortsTags)", "4.0.1-1",
946 N_("header tags are always sorted after being loaded.") },
947 { "rpmlib(ScriptletInterpreterArgs)", "4.0.3-1",
949 N_("the scriptlet interpreter can use arguments from header.") },
950 { "rpmlib(PartialHardlinkSets)", "4.0.4-1",
952 N_("a hardlink file set may be installed without being complete.") },
953 { "rpmlib(ConcurrentAccess)", "4.1-1",
955 N_("package scriptlets may access the rpm database while installing.") },
957 { "rpmlib(BuiltinLuaScripts)", "4.2.2-1",
959 N_("internal support for lua scripts.") },
961 { "rpmlib(FileDigests)", "4.6.0-1",
963 N_("file digest algorithm is per package configurable") },
965 { "rpmlib(FileCaps)", "4.6.1-1",
967 N_("support for POSIX.1e file capabilities") },
969 { NULL, NULL, 0, NULL }
973 int rpmdsRpmlib(rpmds * dsp, void * tblp)
975 const struct rpmlibProvides_s * rltblp = tblp;
976 const struct rpmlibProvides_s * rlp;
980 rltblp = rpmlibProvides;
982 for (rlp = rltblp; rlp->featureName != NULL; rlp++) {
983 rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME, rlp->featureName,
984 rlp->featureEVR, rlp->featureFlags);
985 xx = rpmdsMerge(dsp, ds);