8 #include <rpm/rpmtypes.h>
9 #include <rpm/rpmlib.h>
10 #include <rpm/rpmmacro.h> /* XXX for %_i18ndomains */
11 #include <rpm/rpmfi.h>
12 #include <rpm/rpmstring.h>
13 #include <rpm/rpmlog.h>
14 #include "lib/misc.h" /* tag function proto */
18 struct headerTagFunc_s {
19 rpmTag tag; /*!< Tag of extension. */
20 headerTagTagFunction func; /*!< Pointer to formatter function. */
24 * Retrieve file names from header.
26 * The representation of file names in package headers changed in rpm-4.0.
27 * Originally, file names were stored as an array of absolute paths.
28 * In rpm-4.0, file names are stored as separate arrays of dirname's and
29 * basename's, * with a dirname index to associate the correct dirname
32 * This function is used to retrieve file names independent of how the
33 * file names are represented in the package header.
36 * @param tagN RPMTAG_BASENAMES | PMTAG_ORIGBASENAMES
37 * @param withstate take file state into account?
38 * @retval td tag data container
39 * @return 1 on success
41 static int fnTag(Header h, rpmTag tagN, int withstate, rpmtd td)
43 const char **baseNames, **dirNames;
44 const char *fileStates = NULL;
46 rpm_count_t count, retcount, dncount;
48 rpmTag dirNameTag = RPMTAG_DIRNAMES;
49 rpmTag dirIndexesTag = RPMTAG_DIRINDEXES;
51 int rc = 0; /* assume failure */
52 struct rpmtd_s bnames, dnames, dixs, fstates;
54 if (tagN == RPMTAG_ORIGBASENAMES) {
55 dirNameTag = RPMTAG_ORIGDIRNAMES;
56 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
59 if (!headerGet(h, tagN, &bnames, HEADERGET_MINMEM)) {
60 return 0; /* no file list */
63 (void) headerGet(h, dirNameTag, &dnames, HEADERGET_MINMEM);
64 (void) headerGet(h, dirIndexesTag, &dixs, HEADERGET_MINMEM);
66 retcount = count = rpmtdCount(&bnames);
67 dncount = rpmtdCount(&dnames);
69 /* Basic sanity checking for our interrelated tags */
70 if (rpmtdCount(&dixs) != count || dncount < 1 || dncount > count)
71 td->flags |= RPMTD_INVALID;
74 /* no recorded states means no installed files */
75 if (!headerGet(h, RPMTAG_FILESTATES, &fstates, HEADERGET_MINMEM))
77 if (rpmtdCount(&fstates) != count)
78 td->flags |= RPMTD_INVALID;
79 fileStates = fstates.data;
82 if (td->flags & RPMTD_INVALID)
85 baseNames = bnames.data;
86 dirNames = dnames.data;
87 dirIndexes = dixs.data;
90 * fsm, psm and rpmfi assume the data is stored in a single allocation
91 * block, until those assumptions are removed we need to jump through
92 * a few hoops here and precalculate sizes etc
94 for (i = 0; i < count; i++) {
95 if (fileStates && !RPMFILE_IS_INSTALLED(fileStates[i])) {
99 /* Sanity check directory indexes are within bounds */
100 if (dirIndexes[i] >= dncount) {
101 td->flags |= RPMTD_INVALID;
104 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
107 if (!(td->flags & RPMTD_INVALID)) {
108 char **fileNames = xmalloc(size + (sizeof(*fileNames) * retcount));
109 char *t = ((char *) fileNames) + (sizeof(*fileNames) * retcount);
110 for (i = 0, j = 0; i < count; i++) {
111 if (fileStates && !RPMFILE_IS_INSTALLED(fileStates[i]))
114 t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
118 td->data = fileNames;
119 td->count = retcount;
120 td->type = RPM_STRING_ARRAY_TYPE;
121 td->flags |= RPMTD_ALLOCED;
126 rpmtdFreeData(&bnames);
127 rpmtdFreeData(&dnames);
128 rpmtdFreeData(&dixs);
129 /* only safe if the headerGet() on file states was actually called */
131 rpmtdFreeData(&fstates);
136 static int filedepTag(Header h, rpmTag tagN, rpmtd td, headerGetFlags hgflags)
138 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
146 numfiles = rpmfiFC(fi);
151 if (tagN == RPMTAG_PROVIDENAME)
153 else if (tagN == RPMTAG_REQUIRENAME)
156 ds = rpmdsNew(h, tagN, 0);
157 fdeps = xmalloc(numfiles * sizeof(*fdeps));
159 while ((fileix = rpmfiNext(fi)) >= 0) {
161 const uint32_t * ddict = NULL;
162 int ndx = rpmfiFDepends(fi, &ddict);
166 unsigned dix = *ddict++;
167 char mydt = ((dix >> 24) & 0xff);
171 (void) rpmdsSetIx(ds, dix-1);
172 if (rpmdsNext(ds) < 0)
174 DNEVR = rpmdsDNEVR(ds);
176 argvAdd(&deps, DNEVR + 2);
180 fdeps[fileix] = deps ? argvJoin(deps, " ") : xstrdup("");
184 td->count = numfiles;
185 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
186 td->type = RPM_STRING_ARRAY_TYPE;
195 static char * strtolocale(char *str)
198 const unsigned char *cp;
202 int ccl, cca, mb_cur_max;
212 wstr = (wchar_t *)xmalloc((strlen(str) + 1) * sizeof(*wstr));
214 cp = (const unsigned char *)str;
215 while ((c = *cp++) != 0) {
217 if ((c & 0xc0) != 0x80) {
221 c = (c & 0x3f) | (state << 6);
222 if (!(state & 0x40000000)) {
223 /* check for overlong sequences */
224 if ((c & 0x820823e0) == 0x80000000)
226 else if ((c & 0x020821f0) == 0x02000000)
228 else if ((c & 0x000820f8) == 0x00080000)
230 else if ((c & 0x0000207c) == 0x00002000)
238 c = (c & 0x01) | 0xbffffffc; /* 5 bytes to follow */
240 c = (c & 0x03) | 0xbfffff00; /* 4 */
242 c = (c & 0x07) | 0xbfffc000; /* 3 */
244 c = (c & 0x0f) | 0xbff00000; /* 2 */
246 c = (c & 0x1f) | 0xfc000000; /* 1 */
248 c = 0xfdffffff; /* overlong */
252 state = (c & 0x80000000) ? c : 0;
258 /* encoding error, assume latin1 */
260 cp = (const unsigned char *)str;
262 while ((c = *cp++) != 0) {
267 mb_cur_max = MB_CUR_MAX;
268 memset(&ps, 0, sizeof(ps));
269 cc = xmalloc(mb_cur_max);
270 /* test locale encoding */
271 if (wcrtomb(cc, 0x20ac, &ps) != 3 || memcmp(cc, "\342\202\254", 3))
273 if (locisutf8 == strisutf8) {
278 str = _free((char *)str);
279 memset(&ps, 0, sizeof(ps));
281 for (wp = wstr; ; wp++) {
282 l = wcrtomb(cc + ccl, *wp, &ps);
285 if (l == (size_t)-1) {
286 if (*wp < (wchar_t)256 && mbsinit(&ps)) {
290 l = wcrtomb(cc + ccl, (wchar_t)'?', &ps);
292 if (l == 0 || l == (size_t)-1)
297 cc = xrealloc(cc, cca + mb_cur_max);
305 * Retrieve trigger info.
307 * @retval td tag data container
308 * @return 1 on success
310 static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
315 struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd;
316 int hgeflags = HEADERGET_MINMEM;
318 if (!headerGet(h, RPMTAG_TRIGGERNAME, &nametd, hgeflags)) {
322 headerGet(h, RPMTAG_TRIGGERINDEX, &indextd, hgeflags);
323 headerGet(h, RPMTAG_TRIGGERFLAGS, &flagtd, hgeflags);
324 headerGet(h, RPMTAG_TRIGGERVERSION, &versiontd, hgeflags);
325 headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripttd, hgeflags);
327 td->type = RPM_STRING_ARRAY_TYPE;
328 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
329 td->data = conds = xmalloc(sizeof(*conds) * rpmtdCount(&scripttd));
330 td->count = rpmtdCount(&scripttd);
332 indices = indextd.data;
334 while ((i = rpmtdNext(&scripttd)) >= 0) {
336 char *flagStr, *item;
339 rpmtdInit(&nametd); rpmtdInit(&flagtd); rpmtdInit(&versiontd);
340 while ((j = rpmtdNext(&nametd)) >= 0) {
341 /* flag and version arrays match name array size always */
342 rpmtdNext(&flagtd); rpmtdNext(&versiontd);
347 flag = rpmtdGetUint32(&flagtd);
348 if (flag && *flag & RPMSENSE_SENSEMASK) {
349 flagStr = rpmtdFormat(&flagtd, RPMTD_FORMAT_DEPFLAGS, NULL);
350 rasprintf(&item, "%s %s %s", rpmtdGetString(&nametd),
352 rpmtdGetString(&versiontd));
355 item = xstrdup(rpmtdGetString(&nametd));
358 argvAdd(&items, item);
362 conds[i] = argvJoin(items, ", ");
366 rpmtdFreeData(&nametd);
367 rpmtdFreeData(&versiontd);
368 rpmtdFreeData(&flagtd);
369 rpmtdFreeData(&indextd);
370 rpmtdFreeData(&scripttd);
375 * Retrieve trigger type info.
377 * @retval td tag data container
378 * @return 1 on success
380 static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
384 struct rpmtd_s indices, flags, scripts;
386 if (!headerGet(h, RPMTAG_TRIGGERINDEX, &indices, HEADERGET_MINMEM)) {
390 headerGet(h, RPMTAG_TRIGGERFLAGS, &flags, HEADERGET_MINMEM);
391 headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripts, HEADERGET_MINMEM);
393 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
394 td->count = rpmtdCount(&scripts);
395 td->data = conds = xmalloc(sizeof(*conds) * td->count);
396 td->type = RPM_STRING_ARRAY_TYPE;
398 while ((i = rpmtdNext(&scripts)) >= 0) {
400 rpmtdInit(&indices); rpmtdInit(&flags);
402 while (rpmtdNext(&indices) >= 0 && rpmtdNext(&flags) >= 0) {
403 if (*rpmtdGetUint32(&indices) != i)
406 flag = rpmtdGetUint32(&flags);
407 if (*flag & RPMSENSE_TRIGGERPREIN)
408 conds[i] = xstrdup("prein");
409 else if (*flag & RPMSENSE_TRIGGERIN)
410 conds[i] = xstrdup("in");
411 else if (*flag & RPMSENSE_TRIGGERUN)
412 conds[i] = xstrdup("un");
413 else if (*flag & RPMSENSE_TRIGGERPOSTUN)
414 conds[i] = xstrdup("postun");
416 conds[i] = xstrdup("");
420 rpmtdFreeData(&indices);
421 rpmtdFreeData(&flags);
422 rpmtdFreeData(&scripts);
428 * Retrieve installed file paths.
430 * @retval td tag data container
431 * @return 1 on success
433 static int instfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
435 return fnTag(h, RPMTAG_BASENAMES, 1, td);
438 * Retrieve file paths.
440 * @retval td tag data container
441 * @return 1 on success
443 static int filenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
445 return fnTag(h, RPMTAG_BASENAMES, 0, td);
449 * Retrieve original file paths (wrt relocation).
451 * @retval td tag data container
452 * @return 1 on success
454 static int origfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
456 return fnTag(h, RPMTAG_ORIGBASENAMES, 0, td);
460 * Attempt to generate libmagic-style file class if missing from header:
461 * we can easily generate this for symlinks and other special types.
462 * Always return malloced strings to simplify life in fileclassTag().
464 static char *makeFClass(rpmfi fi)
467 const char *hc = rpmfiFClass(fi);
469 if (hc != NULL && hc[0] != '\0') {
470 fclass = xstrdup(hc);
472 switch (rpmfiFMode(fi) & S_IFMT) {
474 fclass = xstrdup("block special");
477 fclass = xstrdup("character special");
480 fclass = xstrdup("directory");
483 fclass = xstrdup("fifo (named pipe)");
486 fclass = xstrdup("socket");
489 fclass = rstrscat(NULL, "symbolic link to `",
490 rpmfiFLink(fi), "'", NULL);
495 return (fclass != NULL) ? fclass : xstrdup("");
499 * Retrieve/generate file classes.
501 * @retval td tag data container
502 * @return 1 on success
504 static int fileclassTag(Header h, rpmtd td, headerGetFlags hgflags)
506 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
507 int numfiles = rpmfiFC(fi);
510 char **fclasses = xmalloc(numfiles * sizeof(*fclasses));
514 while ((ix = rpmfiNext(fi)) >= 0) {
515 fclasses[ix] = makeFClass(fi);
519 td->count = numfiles;
520 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
521 td->type = RPM_STRING_ARRAY_TYPE;
525 return (numfiles > 0);
529 * Retrieve file provides.
531 * @retval td tag data container
532 * @return 1 on success
534 static int fileprovideTag(Header h, rpmtd td, headerGetFlags hgflags)
536 return filedepTag(h, RPMTAG_PROVIDENAME, td, hgflags);
540 * Retrieve file requires.
542 * @retval td tag data container
543 * @return 1 on success
545 static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags)
547 return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags);
550 /* I18N look aside diversions */
552 #if defined(ENABLE_NLS)
553 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
555 static const char * const language = "LANGUAGE";
557 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
560 * Retrieve i18n text.
563 * @retval td tag data container
564 * @return 1 on success
566 static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags)
569 #if defined(ENABLE_NLS)
570 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
572 td->type = RPM_STRING_TYPE;
576 if (dstring && *dstring) {
578 const char * langval;
582 rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME),
585 /* change to en_US for msgkey -> msgid resolution */
586 langval = getenv(language);
587 (void) setenv(language, "en_US", 1);
591 for (domain = dstring; domain != NULL; domain = de) {
592 de = strchr(domain, ':');
593 if (de) *de++ = '\0';
594 msgid = dgettext(domain, msgkey);
595 if (msgid != msgkey) break;
598 /* restore previous environment for msgid -> msgstr resolution */
600 (void) setenv(language, langval, 1);
605 if (domain && msgid) {
606 td->data = dgettext(domain, msgid);
607 td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */
609 td->flags = RPMTD_ALLOCED;
611 dstring = _free(dstring);
620 rc = headerGet(h, tag, td, HEADERGET_ALLOC);
621 if (rc && td->data) {
622 td->data = strtolocale(td->data);
628 * Retrieve text and convert to locale.
630 static int localeTag(Header h, rpmTag tag, rpmtd td)
633 rc = headerGet(h, tag, td, HEADERGET_ALLOC);
636 if (td->type == RPM_STRING_TYPE) {
637 td->data = strtolocale(td->data);
639 } else if (td->type == RPM_STRING_ARRAY_TYPE) {
642 arr = xmalloc(td->count * sizeof(*arr));
643 for (i = 0; i < td->count; i++) {
644 arr[i] = xstrdup(((char **)td->data)[i]);
645 arr[i] = strtolocale(arr[i]);
649 td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
656 * Retrieve summary text.
658 * @retval td tag data container
659 * @return 1 on success
661 static int summaryTag(Header h, rpmtd td, headerGetFlags hgflags)
663 return i18nTag(h, RPMTAG_SUMMARY, td, hgflags);
667 * Retrieve description text.
669 * @retval td tag data container
670 * @return 1 on success
672 static int descriptionTag(Header h, rpmtd td, headerGetFlags hgflags)
674 return i18nTag(h, RPMTAG_DESCRIPTION, td, hgflags);
677 static int changelognameTag(Header h, rpmtd td)
679 return localeTag(h, RPMTAG_CHANGELOGNAME, td);
682 static int changelogtextTag(Header h, rpmtd td)
684 return localeTag(h, RPMTAG_CHANGELOGTEXT, td);
688 * Retrieve group text.
690 * @retval td tag data container
691 * @return 1 on success
693 static int groupTag(Header h, rpmtd td, headerGetFlags hgflags)
695 return i18nTag(h, RPMTAG_GROUP, td, hgflags);
699 * Helper to convert 32bit tag to 64bit version.
700 * If header has new 64bit tag then just return the data,
701 * otherwise convert 32bit old tag data to 64bit values.
702 * For consistency, always return malloced data.
704 static int get64(Header h, rpmtd td, rpmTag newtag, rpmTag oldtag)
708 if (headerIsEntry(h, newtag)) {
709 rc = headerGet(h, newtag, td, HEADERGET_ALLOC);
711 struct rpmtd_s olddata;
712 uint32_t *d32 = NULL;
713 uint64_t *d64 = NULL;
715 headerGet(h, oldtag, &olddata, HEADERGET_MINMEM);
716 if (rpmtdType(&olddata) == RPM_INT32_TYPE) {
717 td->type = RPM_INT64_TYPE;
718 td->count = olddata.count;
719 td->flags = RPMTD_ALLOCED;
720 td->data = xmalloc(sizeof(*d64) * td->count);
722 while ((d32 = rpmtdNextUint32(&olddata))) {
726 rpmtdFreeData(&olddata);
734 * Retrieve file sizes as 64bit regardless of how they're stored.
736 * @retval td tag data container
737 * @return 1 on success
739 static int longfilesizesTag(Header h, rpmtd td, headerGetFlags hgflags)
741 return get64(h, td, RPMTAG_LONGFILESIZES, RPMTAG_FILESIZES);
744 static int longarchivesizeTag(Header h, rpmtd td, headerGetFlags hgflags)
746 return get64(h, td, RPMTAG_LONGARCHIVESIZE, RPMTAG_ARCHIVESIZE);
749 static int longsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
751 return get64(h, td, RPMTAG_LONGSIZE, RPMTAG_SIZE);
754 static int longsigsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
756 return get64(h, td, RPMTAG_LONGSIGSIZE, RPMTAG_SIGSIZE);
759 static int numberTag(rpmtd td, uint32_t val)
761 uint32_t *tval = xmalloc(sizeof(*tval));
764 td->type = RPM_INT32_TYPE;
767 td->flags = RPMTD_ALLOCED;
768 return 1; /* this cannot fail */
771 static int dbinstanceTag(Header h, rpmtd td, headerGetFlags hgflags)
773 return numberTag(td, headerGetInstance(h));
776 static int headercolorTag(Header h, rpmtd td, headerGetFlags hgflags)
778 rpm_color_t *fcolor, hcolor = 0;
779 struct rpmtd_s fcolors;
781 headerGet(h, RPMTAG_FILECOLORS, &fcolors, HEADERGET_MINMEM);
782 while ((fcolor = rpmtdNextUint32(&fcolors)) != NULL) {
785 rpmtdFreeData(&fcolors);
788 return numberTag(td, hcolor);
792 NEVRA_NAME = (1 << 0),
793 NEVRA_EPOCH = (1 << 1),
794 NEVRA_VERSION = (1 << 2),
795 NEVRA_RELEASE = (1 << 3),
796 NEVRA_ARCH = (1 << 4)
798 typedef rpmFlags nevraFlags;
800 static int getNEVRA(Header h, rpmtd td, nevraFlags flags)
802 const char *val = NULL;
805 if ((flags & NEVRA_NAME)) {
806 val = headerGetString(h, RPMTAG_NAME);
807 if (val) rstrscat(&res, val, "-", NULL);
809 if ((flags & NEVRA_EPOCH)) {
810 char *e = headerGetAsString(h, RPMTAG_EPOCH);
811 if (e) rstrscat(&res, e, ":", NULL);
814 if ((flags & NEVRA_VERSION)) {
815 val = headerGetString(h, RPMTAG_VERSION);
816 if (val) rstrscat(&res, val, "-", NULL);
818 if ((flags & NEVRA_RELEASE)) {
819 val = headerGetString(h, RPMTAG_RELEASE);
820 if (val) rstrscat(&res, val, NULL);
822 if ((flags & NEVRA_ARCH)) {
823 val = headerGetString(h, RPMTAG_ARCH);
824 if (headerIsSource(h) && val == NULL) val = "src";
825 if (val) rstrscat(&res, ".", val, NULL);
828 td->type = RPM_STRING_TYPE;
831 td->flags = RPMTD_ALLOCED;
836 static int evrTag(Header h, rpmtd td, headerGetFlags hgflags)
838 return getNEVRA(h, td, NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
841 static int nvrTag(Header h, rpmtd td, headerGetFlags hgflags)
843 return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE);
846 static int nvraTag(Header h, rpmtd td, headerGetFlags hgflags)
848 return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
851 static int nevrTag(Header h, rpmtd td, headerGetFlags hgflags)
853 return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
856 static int nevraTag(Header h, rpmtd td, headerGetFlags hgflags)
858 return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
861 static int verboseTag(Header h, rpmtd td, headerGetFlags hgflags)
863 if (rpmIsVerbose()) {
864 td->type = RPM_INT32_TYPE;
866 td->data = &(td->count);
867 td->flags = RPMTD_NONE;
874 static int epochnumTag(Header h, rpmtd td, headerGetFlags hgflags)
876 /* For consistency, always return malloced data */
877 if (!headerGet(h, RPMTAG_EPOCH, td, HEADERGET_ALLOC)) {
878 uint32_t *e = malloc(sizeof(*e));
881 td->type = RPM_INT32_TYPE;
883 td->flags = RPMTD_ALLOCED;
885 td->tag = RPMTAG_EPOCHNUM;
889 static int depnevrsTag(Header h, rpmtd td, headerGetFlags hgflags,
892 rpmds ds = rpmdsNew(h, tag, 0);
893 int ndeps = rpmdsCount(ds);
896 char **deps = xmalloc(sizeof(*deps) * ndeps);
898 while ((i = rpmdsNext(ds)) >= 0) {
899 deps[i] = rpmdsNewDNEVR(NULL, ds);
902 td->type = RPM_STRING_ARRAY_TYPE;
904 td->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED);
910 static int requirenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
912 return depnevrsTag(h, td, hgflags, RPMTAG_REQUIRENAME);
915 static int providenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
917 return depnevrsTag(h, td, hgflags, RPMTAG_PROVIDENAME);
920 static int obsoletenevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
922 return depnevrsTag(h, td, hgflags, RPMTAG_OBSOLETENAME);
925 static int conflictnevrsTag(Header h, rpmtd td, headerGetFlags hgflags)
927 return depnevrsTag(h, td, hgflags, RPMTAG_CONFLICTNAME);
930 static int filenlinksTag(Header h, rpmtd td, headerGetFlags hgflags)
932 rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
933 rpm_count_t fc = rpmfiFC(fi);
936 uint32_t *nlinks = xmalloc(fc * sizeof(*nlinks));
938 while ((ix = rpmfiNext(fi)) >= 0) {
939 nlinks[ix] = rpmfiFNlink(fi);
942 td->type = RPM_INT32_TYPE;
944 td->flags = RPMTD_ALLOCED;
951 static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
952 { RPMTAG_GROUP, groupTag },
953 { RPMTAG_DESCRIPTION, descriptionTag },
954 { RPMTAG_SUMMARY, summaryTag },
955 { RPMTAG_FILECLASS, fileclassTag },
956 { RPMTAG_FILENAMES, filenamesTag },
957 { RPMTAG_ORIGFILENAMES, origfilenamesTag },
958 { RPMTAG_FILEPROVIDE, fileprovideTag },
959 { RPMTAG_FILEREQUIRE, filerequireTag },
960 { RPMTAG_TRIGGERCONDS, triggercondsTag },
961 { RPMTAG_TRIGGERTYPE, triggertypeTag },
962 { RPMTAG_LONGFILESIZES, longfilesizesTag },
963 { RPMTAG_LONGARCHIVESIZE, longarchivesizeTag },
964 { RPMTAG_LONGSIZE, longsizeTag },
965 { RPMTAG_LONGSIGSIZE, longsigsizeTag },
966 { RPMTAG_CHANGELOGNAME, changelognameTag },
967 { RPMTAG_CHANGELOGTEXT, changelogtextTag },
968 { RPMTAG_DBINSTANCE, dbinstanceTag },
969 { RPMTAG_EVR, evrTag },
970 { RPMTAG_NVR, nvrTag },
971 { RPMTAG_NEVR, nevrTag },
972 { RPMTAG_NVRA, nvraTag },
973 { RPMTAG_NEVRA, nevraTag },
974 { RPMTAG_HEADERCOLOR, headercolorTag },
975 { RPMTAG_VERBOSE, verboseTag },
976 { RPMTAG_EPOCHNUM, epochnumTag },
977 { RPMTAG_INSTFILENAMES, instfilenamesTag },
978 { RPMTAG_REQUIRENEVRS, requirenevrsTag },
979 { RPMTAG_PROVIDENEVRS, providenevrsTag },
980 { RPMTAG_OBSOLETENEVRS, obsoletenevrsTag },
981 { RPMTAG_CONFLICTNEVRS, conflictnevrsTag },
982 { RPMTAG_FILENLINKS, filenlinksTag },
986 headerTagTagFunction rpmHeaderTagFunc(rpmTagVal tag)
988 const struct headerTagFunc_s * ext;
989 headerTagTagFunction func = NULL;
991 for (ext = rpmHeaderTagExtensions; ext->func != NULL; ext++) {
992 if (ext->tag == tag) {