lib/formats.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmio_internal.h"
00008 #include <rpmlib.h>
00009 #include <rpmmacro.h>   /* XXX for %_i18ndomains */
00010 #include <rpmuuid.h>
00011 
00012 #define _RPMEVR_INTERNAL
00013 #include <rpmds.h>
00014 #include <rpmfi.h>
00015 
00016 #include "legacy.h"
00017 #include "argv.h"
00018 #include "ugid.h"
00019 #include "misc.h"
00020 #include "fs.h"
00021 
00022 #include "debug.h"
00023 
00024 /*@access pgpDig @*/
00025 /*@access pgpDigParams @*/
00026 
00027 /* XXX FIXME: static for now, refactor from manifest.c later. */
00028 static char * rpmPermsString(int mode)
00029         /*@*/
00030 {
00031     char *perms = xstrdup("----------");
00032    
00033     if (S_ISREG(mode)) 
00034         perms[0] = '-';
00035     else if (S_ISDIR(mode)) 
00036         perms[0] = 'd';
00037     else if (S_ISLNK(mode))
00038         perms[0] = 'l';
00039     else if (S_ISFIFO(mode)) 
00040         perms[0] = 'p';
00041     /*@-unrecog@*/
00042     else if (S_ISSOCK(mode)) 
00043         perms[0] = 's';
00044     /*@=unrecog@*/
00045     else if (S_ISCHR(mode))
00046         perms[0] = 'c';
00047     else if (S_ISBLK(mode))
00048         perms[0] = 'b';
00049     else
00050         perms[0] = '?';
00051 
00052     if (mode & S_IRUSR) perms[1] = 'r';
00053     if (mode & S_IWUSR) perms[2] = 'w';
00054     if (mode & S_IXUSR) perms[3] = 'x';
00055  
00056     if (mode & S_IRGRP) perms[4] = 'r';
00057     if (mode & S_IWGRP) perms[5] = 'w';
00058     if (mode & S_IXGRP) perms[6] = 'x';
00059 
00060     if (mode & S_IROTH) perms[7] = 'r';
00061     if (mode & S_IWOTH) perms[8] = 'w';
00062     if (mode & S_IXOTH) perms[9] = 'x';
00063 
00064     if (mode & S_ISUID)
00065         perms[3] = ((mode & S_IXUSR) ? 's' : 'S'); 
00066 
00067     if (mode & S_ISGID)
00068         perms[6] = ((mode & S_IXGRP) ? 's' : 'S'); 
00069 
00070     if (mode & S_ISVTX)
00071         perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
00072 
00073     return perms;
00074 }
00075 
00082 static /*@only@*/ char * triggertypeFormat(HE_t he, /*@null@*/ const char ** av)
00083 {
00084     rpmTagData data = { .ptr = he->p.ptr };
00085     int ix = (he->ix > 0 ? he->ix : 0);
00086     char * val;
00087 
00088 assert(ix == 0);
00089     if (he->t != RPM_INT64_TYPE)
00090         val = xstrdup(_("(invalid type)"));
00091     else {
00092         int anint = data.i64p[ix];
00093         if (anint & RPMSENSE_TRIGGERPREIN)
00094             val = xstrdup("prein");
00095         else if (anint & RPMSENSE_TRIGGERIN)
00096             val = xstrdup("in");
00097         else if (anint & RPMSENSE_TRIGGERUN)
00098             val = xstrdup("un");
00099         else if (anint & RPMSENSE_TRIGGERPOSTUN)
00100             val = xstrdup("postun");
00101         else
00102             val = xstrdup("");
00103     }
00104     return val;
00105 }
00106 
00113 static /*@only@*/ char * permsFormat(HE_t he, /*@null@*/ const char ** av)
00114 {
00115     int ix = (he->ix > 0 ? he->ix : 0);
00116     char * val;
00117 
00118 assert(ix == 0);
00119     if (he->t != RPM_INT64_TYPE) {
00120         val = xstrdup(_("(invalid type)"));
00121     } else {
00122         int_32 anint = he->p.i64p[0];
00123         val = rpmPermsString(anint);
00124     }
00125 
00126     return val;
00127 }
00128 
00135 static /*@only@*/ char * fflagsFormat(HE_t he, /*@null@*/ const char ** av)
00136 {
00137     rpmTagData data = { .ptr = he->p.ptr };
00138     int ix = (he->ix >= 0 ? he->ix : 0);
00139     char * val;
00140 
00141 assert(ix == 0);
00142     if (he->t != RPM_INT64_TYPE) {
00143         val = xstrdup(_("(invalid type)"));
00144     } else {
00145         char buf[15];
00146         unsigned anint = data.i64p[ix];
00147         buf[0] = '\0';
00148         if (anint & RPMFILE_DOC)
00149             strcat(buf, "d");
00150         if (anint & RPMFILE_CONFIG)
00151             strcat(buf, "c");
00152         if (anint & RPMFILE_SPECFILE)
00153             strcat(buf, "s");
00154         if (anint & RPMFILE_MISSINGOK)
00155             strcat(buf, "m");
00156         if (anint & RPMFILE_NOREPLACE)
00157             strcat(buf, "n");
00158         if (anint & RPMFILE_GHOST)
00159             strcat(buf, "g");
00160         if (anint & RPMFILE_LICENSE)
00161             strcat(buf, "l");
00162         if (anint & RPMFILE_README)
00163             strcat(buf, "r");
00164         val = xstrdup(buf);
00165     }
00166 
00167     return val;
00168 }
00169 
00177 static /*@only@*/ char * armorFormat(HE_t he, /*@null@*/ const char ** av)
00178         /*@*/
00179 {
00180     rpmTagData data = { .ptr = he->p.ptr };
00181     int ix = (he->ix > 0 ? he->ix : 0);
00182     const char * enc;
00183     const unsigned char * s;
00184     size_t ns;
00185     int atype;
00186     char * val;
00187 
00188 assert(ix == 0);
00189     switch (he->t) {
00190     case RPM_OPENPGP_TYPE:
00191     case RPM_ASN1_TYPE:         /* XXX WRONG */
00192     case RPM_BIN_TYPE:
00193         s = data.ui8p;
00194         ns = he->c;
00195         atype = PGPARMOR_SIGNATURE;     /* XXX check pkt for signature */
00196         break;
00197     case RPM_STRING_TYPE:
00198     case RPM_STRING_ARRAY_TYPE:
00199         enc = data.str;
00200         s = NULL;
00201         ns = 0;
00202 /*@-moduncon@*/
00203         if (b64decode(enc, (void **)&s, &ns))
00204             return xstrdup(_("(not base64)"));
00205 /*@=moduncon@*/
00206         atype = PGPARMOR_PUBKEY;        /* XXX check pkt for pubkey */
00207         break;
00208     case RPM_NULL_TYPE:
00209     case RPM_CHAR_TYPE:
00210     case RPM_INT8_TYPE:
00211     case RPM_INT16_TYPE:
00212     case RPM_INT32_TYPE:
00213     case RPM_INT64_TYPE:
00214     case RPM_I18NSTRING_TYPE:
00215     default:
00216         return xstrdup(_("(invalid type)"));
00217         /*@notreached@*/ break;
00218     }
00219 
00220     val = pgpArmorWrap(atype, s, ns);
00221     if (atype == PGPARMOR_PUBKEY)
00222         s = _free(s);
00223     return val;
00224 }
00225 
00233 static /*@only@*/ char * base64Format(HE_t he, /*@null@*/ const char ** av)
00234         /*@*/
00235 {
00236     rpmTagData data = { .ptr = he->p.ptr };
00237     int ix = (he->ix > 0 ? he->ix : 0);
00238     char * val;
00239 
00240 assert(ix == 0);
00241     if (!(he->t == RPM_BIN_TYPE || he->t == RPM_ASN1_TYPE || he->t == RPM_OPENPGP_TYPE)) {
00242         val = xstrdup(_("(not a blob)"));
00243     } else {
00244         const char * enc;
00245         char * t;
00246         int lc;
00247         size_t ns = he->c;
00248         size_t nt = ((ns + 2) / 3) * 4;
00249 
00250         /*@-globs@*/
00251         /* Add additional bytes necessary for eol string(s). */
00252         if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
00253             lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
00254         if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
00255             ++lc;
00256             nt += lc * strlen(b64encode_eolstr);
00257         }
00258         /*@=globs@*/
00259 
00260         val = t = xcalloc(1, nt + 1);
00261         *t = '\0';
00262 
00263     /* XXX b64encode accesses uninitialized memory. */
00264     {   unsigned char * _data = xcalloc(1, ns+1);
00265         memcpy(_data, data.ptr, ns);
00266 /*@-moduncon@*/
00267         if ((enc = b64encode(_data, ns)) != NULL) {
00268             t = stpcpy(t, enc);
00269             enc = _free(enc);
00270         }
00271 /*@=moduncon@*/
00272         _data = _free(_data);
00273     }
00274     }
00275 
00276 /*@-globstate@*/
00277     return val;
00278 /*@=globstate@*/
00279 }
00280 
00286 static size_t xmlstrlen(const char * s)
00287         /*@*/
00288 {
00289     size_t len = 0;
00290     int c;
00291 
00292     while ((c = *s++) != '\0')
00293     {
00294         switch (c) {
00295         case '<':
00296         case '>':       len += sizeof("&lt;") - 1;      /*@switchbreak@*/ break;
00297         case '&':       len += sizeof("&amp;") - 1;     /*@switchbreak@*/ break;
00298         default:        len += 1;                       /*@switchbreak@*/ break;
00299         }
00300     }
00301     return len;
00302 }
00303 
00310 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
00311         /*@modifies t @*/
00312 {
00313     char * te = t;
00314     int c;
00315 
00316     while ((c = *s++) != '\0') {
00317         switch (c) {
00318         case '<':       te = stpcpy(te, "&lt;");        /*@switchbreak@*/ break;
00319         case '>':       te = stpcpy(te, "&gt;");        /*@switchbreak@*/ break;
00320         case '&':       te = stpcpy(te, "&amp;");       /*@switchbreak@*/ break;
00321         default:        *te++ = c;                      /*@switchbreak@*/ break;
00322         }
00323     }
00324     *te = '\0';
00325     return t;
00326 }
00327 
00328 static /*@only@*/ /*@null@*/ char *
00329 strdup_locale_convert (/*@null@*/ const char * buffer,
00330                 /*@null@*/ const char * tocode)
00331         /*@*/
00332 {
00333     char *dest_str;
00334 #if defined(HAVE_ICONV)
00335     char *fromcode = NULL;
00336     iconv_t fd;
00337 
00338     if (buffer == NULL)
00339         return NULL;
00340 
00341     if (tocode == NULL)
00342         tocode = "UTF-8";
00343 
00344 #ifdef HAVE_LANGINFO_H
00345 /*@-type@*/
00346     fromcode = nl_langinfo (CODESET);
00347 /*@=type@*/
00348 #endif
00349 
00350     if (fromcode != NULL && strcmp(tocode, fromcode) != 0
00351      && (fd = iconv_open(tocode, fromcode)) != (iconv_t)-1)
00352     {
00353         const char *pin = buffer;
00354         char *pout = NULL;
00355         size_t ib, ob, dest_size;
00356         int done;
00357         int is_error;
00358         size_t err;
00359         const char *shift_pin = NULL;
00360         int xx;
00361 
00362         err = iconv(fd, NULL, &ib, &pout, &ob);
00363         dest_size = ob = ib = strlen(buffer);
00364         dest_str = pout = malloc((dest_size + 1) * sizeof(*dest_str));
00365         if (dest_str)
00366             *dest_str = '\0';
00367         done = is_error = 0;
00368         if (pout != NULL)
00369         while (done == 0 && is_error == 0) {
00370             err = iconv(fd, (char **)&pin, &ib, &pout, &ob);
00371 
00372             if (err == (size_t)-1) {
00373                 switch (errno) {
00374                 case EINVAL:
00375                     done = 1;
00376                     /*@switchbreak@*/ break;
00377                 case E2BIG:
00378                 {   size_t used = (size_t)(pout - dest_str);
00379                     dest_size *= 2;
00380                     dest_str = realloc(dest_str, (dest_size + 1) * sizeof(*dest_str));
00381                     if (dest_str == NULL) {
00382                         is_error = 1;
00383                         continue;
00384                     }
00385                     pout = dest_str + used;
00386                     ob = dest_size - used;
00387                 }   /*@switchbreak@*/ break;
00388                 case EILSEQ:
00389                     is_error = 1;
00390                     /*@switchbreak@*/ break;
00391                 default:
00392                     is_error = 1;
00393                     /*@switchbreak@*/ break;
00394                 }
00395             } else {
00396                 if (shift_pin == NULL) {
00397                     shift_pin = pin;
00398                     pin = NULL;
00399                     ib = 0;
00400                 } else {
00401                     done = 1;
00402                 }
00403             }
00404         }
00405         xx = iconv_close(fd);
00406         if (pout)
00407             *pout = '\0';
00408         if (dest_str != NULL)
00409             dest_str = xstrdup(dest_str);
00410     } else
00411 #endif
00412     {
00413         dest_str = xstrdup((buffer ? buffer : ""));
00414     }
00415 
00416     return dest_str;
00417 }
00418 
00425 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av)
00426         /*@*/
00427 {
00428     int ix = (he->ix > 0 ? he->ix : 0);
00429     char * val;
00430 
00431 assert(ix == 0);
00432     if (he->t != RPM_STRING_TYPE) {
00433         val = xstrdup(_("(not a string)"));
00434     } else {
00435         const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
00436         size_t nb = xmlstrlen(s);
00437         char * t;
00438 
00439         val = t = xcalloc(1, nb + 1);
00440         t = xmlstrcpy(t, s);    t += strlen(t);
00441         *t = '\0';
00442         s = _free(s);
00443     }
00444 
00445 /*@-globstate@*/
00446     return val;
00447 /*@=globstate@*/
00448 }
00449 
00456 static /*@only@*/ char * iconvFormat(HE_t he, /*@null@*/ const char ** av)
00457         /*@*/
00458 {
00459     int ix = (he->ix > 0 ? he->ix : 0);
00460     char * val;
00461 
00462 assert(ix == 0);
00463     if (he->t != RPM_STRING_TYPE) {
00464         val = xstrdup(_("(not a string)"));
00465     } else {
00466         val = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
00467     }
00468 
00469 /*@-globstate@*/
00470     return val;
00471 /*@=globstate@*/
00472 }
00473 
00480 static /*@only@*/ char * xmlFormat(HE_t he, /*@null@*/ const char ** av)
00481         /*@*/
00482 {
00483     rpmTagData data = { .ptr = he->p.ptr };
00484     int ix = (he->ix > 0 ? he->ix : 0);
00485     const char * xtag = NULL;
00486     size_t nb;
00487     char * val;
00488     const char * s = NULL;
00489     char * t, * te;
00490     unsigned long long anint = 0;
00491     int freeit = 0;
00492     int xx;
00493 
00494 assert(ix == 0);
00495 assert(he->t == RPM_STRING_TYPE || he->t == RPM_INT64_TYPE || he->t == RPM_BIN_TYPE);
00496     switch (he->t) {
00497     case RPM_STRING_ARRAY_TYPE:
00498         s = data.argv[ix];
00499         xtag = "string";
00500         /* XXX Force utf8 strings. */
00501         s = xstrdup(s);
00502         s = xstrtolocale(s);
00503         freeit = 1;
00504         break;
00505     case RPM_I18NSTRING_TYPE:
00506     case RPM_STRING_TYPE:
00507         s = data.str;
00508         xtag = "string";
00509         /* XXX Force utf8 strings. */
00510         s = xstrdup(s);
00511         s = xstrtolocale(s);
00512         freeit = 1;
00513         break;
00514     case RPM_OPENPGP_TYPE:
00515     case RPM_ASN1_TYPE:
00516     case RPM_BIN_TYPE:
00517 /*@-globs -mods@*/
00518     {   int cpl = b64encode_chars_per_line;
00519         b64encode_chars_per_line = 0;
00520 /*@-formatconst@*/
00521         s = base64Format(he, NULL);
00522 /*@=formatconst@*/
00523         b64encode_chars_per_line = cpl;
00524         xtag = "base64";
00525         freeit = 1;
00526     }   break;
00527 /*@=globs =mods@*/
00528     case RPM_CHAR_TYPE:
00529     case RPM_INT8_TYPE:
00530         anint = data.i8p[ix];
00531         break;
00532     case RPM_INT16_TYPE:
00533         anint = data.ui16p[ix]; /* XXX note unsigned */
00534         break;
00535     case RPM_INT32_TYPE:
00536         anint = data.i32p[ix];
00537         break;
00538     case RPM_INT64_TYPE:
00539         anint = data.i64p[ix];
00540         break;
00541     case RPM_NULL_TYPE:
00542     default:
00543         return xstrdup(_("(invalid xml type)"));
00544         /*@notreached@*/ break;
00545     }
00546 
00547     if (s == NULL) {
00548         int tlen = 64;
00549         t = memset(alloca(tlen+1), 0, tlen+1);
00550 /*@-duplicatequals@*/
00551         if (anint != 0)
00552             xx = snprintf(t, tlen, "%llu", anint);
00553 /*@=duplicatequals@*/
00554         s = t;
00555         xtag = "integer";
00556     }
00557 
00558     nb = xmlstrlen(s);
00559     if (nb == 0) {
00560         nb += strlen(xtag) + sizeof("\t</>");
00561         te = t = alloca(nb);
00562         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
00563     } else {
00564         nb += 2 * strlen(xtag) + sizeof("\t<></>");
00565         te = t = alloca(nb);
00566         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
00567         te = xmlstrcpy(te, s);
00568         te += strlen(te);
00569         te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
00570     }
00571 
00572     if (freeit)
00573         s = _free(s);
00574 
00575     val = xstrdup(t);
00576 
00577     return val;
00578 }
00579 
00586 static size_t yamlstrlen(const char * s, int lvl)
00587         /*@*/
00588 {
00589     size_t len = 0;
00590     int indent = (lvl > 0);
00591     int c;
00592 
00593     while ((c = (int) *s++) != (int) '\0')
00594     {
00595         if (indent) {
00596             len += 2 * lvl;
00597             indent = 0;
00598         }
00599         if (c == (int) '\n')
00600             indent = (lvl > 0);
00601         len++;
00602     }
00603     return len;
00604 }
00605 
00613 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s, int lvl)
00614         /*@modifies t @*/
00615 {
00616     char * te = t;
00617     int indent = (lvl > 0);
00618     int c;
00619 
00620     while ((c = (int) *s++) != (int) '\0') {
00621         if (indent) {
00622             int i;
00623             for (i = 0; i < lvl; i++) {
00624                 *te++ = ' ';
00625                 *te++ = ' ';
00626             }
00627             indent = 0;
00628         }
00629         if (c == (int) '\n')
00630             indent = (lvl > 0);
00631         *te++ = (char) c;
00632     }
00633     *te = '\0';
00634     return t;
00635 }
00636 
00643 static /*@only@*/ char * yamlFormat(HE_t he, /*@null@*/ const char ** av)
00644         /*@*/
00645 {
00646     int element = he->ix;
00647     int ix = (he->ix > 0 ? he->ix : 0);
00648     const char * xtag = NULL;
00649     size_t nb;
00650     char * val;
00651     const char * s = NULL;
00652     char * t, * te;
00653     unsigned long long anint = 0;
00654     int freeit = 0;
00655     int lvl = 0;
00656     int xx;
00657     int c;
00658 
00659 assert(ix == 0);
00660 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
00661     xx = 0;
00662     switch (he->t) {
00663     case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
00664     case RPM_I18NSTRING_TYPE:   /* XXX currently never happens */
00665     case RPM_STRING_TYPE:
00666         s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
00667         if (strchr("[", s[0]))  /* leading [ */
00668             xx = 1;
00669         if (xx == 0)
00670         while ((c = (int) *s++) != (int) '\0') {
00671             switch (c) {
00672             default:
00673                 continue;
00674             case '\n':  /* multiline */
00675                 xx = 1;
00676                 /*@switchbreak@*/ break;
00677             case '-':   /* leading "- \"" */
00678             case ':':   /* embedded ": " or ":" at EOL */
00679                 if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
00680                     continue;
00681                 xx = 1;
00682                 /*@switchbreak@*/ break;
00683             }
00684             /*@loopbreak@*/ break;
00685         }
00686         if (xx) {
00687             if (element >= 0) {
00688                 xtag = "- |-\n";
00689                 lvl = 3;
00690             } else {
00691                 xtag = "|-\n";
00692                 lvl = 2;
00693                 if (he->ix < 0) lvl++;  /* XXX extra indent for array[1] */
00694             }
00695         } else {
00696             xtag = (element >= 0 ? "- " : NULL);
00697         }
00698 
00699         /* XXX Force utf8 strings. */
00700         s = xstrdup(he->p.str);
00701         s = xstrtolocale(s);
00702         freeit = 1;
00703         break;
00704     case RPM_OPENPGP_TYPE:
00705     case RPM_ASN1_TYPE:
00706     case RPM_BIN_TYPE:
00707 /*@-globs -mods@*/
00708     {   int cpl = b64encode_chars_per_line;
00709         b64encode_chars_per_line = 0;
00710 /*@-formatconst@*/
00711         s = base64Format(he, NULL);
00712         element = -element;     /* XXX skip "    " indent. */
00713 /*@=formatconst@*/
00714         b64encode_chars_per_line = cpl;
00715         xtag = "!!binary ";
00716         freeit = 1;
00717     }   break;
00718 /*@=globs =mods@*/
00719     case RPM_CHAR_TYPE:
00720     case RPM_UINT8_TYPE:
00721         anint = he->p.ui8p[ix];
00722         break;
00723     case RPM_UINT16_TYPE:
00724         anint = he->p.ui16p[ix];
00725         break;
00726     case RPM_UINT32_TYPE:
00727         anint = he->p.ui32p[ix];
00728         break;
00729     case RPM_UINT64_TYPE:
00730         anint = he->p.ui64p[ix];
00731         break;
00732     case RPM_NULL_TYPE:
00733     default:
00734         return xstrdup(_("(invalid yaml type)"));
00735         /*@notreached@*/ break;
00736     }
00737 
00738     if (s == NULL) {
00739         int tlen = 64;
00740         t = memset(alloca(tlen+1), 0, tlen+1);
00741 /*@-duplicatequals@*/
00742         xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
00743 /*@=duplicatequals@*/
00744         s = t;
00745         xtag = (element >= 0 ? "- " : NULL);
00746     }
00747 
00748     nb = yamlstrlen(s, lvl);
00749     if (nb == 0) {
00750         if (element >= 0)
00751             nb += sizeof("    ") - 1;
00752         nb += sizeof("- ~") - 1;
00753         nb++;
00754         te = t = alloca(nb);
00755         if (element >= 0)
00756             te = stpcpy(te, "    ");
00757         te = stpcpy(te, "- ~");
00758     } else {
00759         if (element >= 0)
00760             nb += sizeof("    ") - 1;
00761         if (xtag)
00762             nb += strlen(xtag);
00763         nb++;
00764         te = t = alloca(nb);
00765         if (element >= 0)
00766             te = stpcpy(te, "    ");
00767         if (xtag)
00768             te = stpcpy(te, xtag);
00769         te = yamlstrcpy(te, s, lvl);
00770         te += strlen(te);
00771     }
00772 
00773     /* XXX s was malloc'd */
00774     if (freeit)
00775         s = _free(s);
00776 
00777     val = xstrdup(t);
00778 
00779     return val;
00780 }
00781 
00788 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@null@*/ const char ** av)
00789         /*@globals fileSystem, internalState @*/
00790         /*@modifies fileSystem, internalState @*/
00791 {
00792     rpmTagData data = { .ptr = he->p.ptr };
00793     int ix = (he->ix > 0 ? he->ix : 0);
00794     char * val, * t;
00795 
00796 assert(ix == 0);
00797     if (!(he->t == RPM_BIN_TYPE || he->t == RPM_ASN1_TYPE || he->t == RPM_OPENPGP_TYPE)) {
00798         val = xstrdup(_("(not a blob)"));
00799     } else {
00800         unsigned char * pkt = (byte *) data.ptr;
00801         unsigned int pktlen = 0;
00802         unsigned int v = *pkt;
00803         pgpTag tag = 0;
00804         unsigned int plen;
00805         unsigned int hlen = 0;
00806 
00807         if (v & 0x80) {
00808             if (v & 0x40) {
00809                 tag = (v & 0x3f);
00810                 plen = pgpLen(pkt+1, &hlen);
00811             } else {
00812                 tag = (v >> 2) & 0xf;
00813                 plen = (1 << (v & 0x3));
00814                 hlen = pgpGrab(pkt+1, plen);
00815             }
00816         
00817             pktlen = 1 + plen + hlen;
00818         }
00819 
00820         if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
00821             val = xstrdup(_("(not an OpenPGP signature)"));
00822         } else {
00823             pgpDig dig = pgpNewDig();
00824             pgpDigParams sigp = &dig->signature;
00825             size_t nb = 0;
00826             const char *tempstr;
00827 
00828             (void) pgpPrtPkts(pkt, pktlen, dig, 0);
00829 
00830             val = NULL;
00831         again:
00832             nb += 100;
00833             val = t = xrealloc(val, nb + 1);
00834 
00835             switch (sigp->pubkey_algo) {
00836             case PGPPUBKEYALGO_DSA:
00837                 t = stpcpy(t, "DSA");
00838                 break;
00839             case PGPPUBKEYALGO_RSA:
00840                 t = stpcpy(t, "RSA");
00841                 break;
00842             default:
00843                 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
00844                 t += strlen(t);
00845                 break;
00846             }
00847             if (t + 5 >= val + nb)
00848                 goto again;
00849             *t++ = '/';
00850             switch (sigp->hash_algo) {
00851             case PGPHASHALGO_MD5:
00852                 t = stpcpy(t, "MD5");
00853                 break;
00854             case PGPHASHALGO_SHA1:
00855                 t = stpcpy(t, "SHA1");
00856                 break;
00857             default:
00858                 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
00859                 t += strlen(t);
00860                 break;
00861             }
00862             if (t + strlen (", ") + 1 >= val + nb)
00863                 goto again;
00864 
00865             t = stpcpy(t, ", ");
00866 
00867             /* this is important if sizeof(int_32) ! sizeof(time_t) */
00868             {   time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
00869                 struct tm * tstruct = localtime(&dateint);
00870                 if (tstruct)
00871                     (void) strftime(t, (nb - (t - val)), "%c", tstruct);
00872             }
00873             t += strlen(t);
00874             if (t + strlen (", Key ID ") + 1 >= val + nb)
00875                 goto again;
00876             t = stpcpy(t, ", Key ID ");
00877             tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
00878             if (t + strlen (tempstr) > val + nb)
00879                 goto again;
00880             t = stpcpy(t, tempstr);
00881 
00882             dig = pgpFreeDig(dig);
00883         }
00884     }
00885 
00886     return val;
00887 }
00888 
00895 static /*@only@*/ char * depflagsFormat(HE_t he, /*@null@*/ const char ** av)
00896         /*@*/
00897 {
00898     rpmTagData data = { .ptr = he->p.ptr };
00899     int ix = (he->ix > 0 ? he->ix : 0);;
00900     char * val;
00901 
00902 assert(ix == 0);
00903     if (he->t != RPM_INT64_TYPE) {
00904         val = xstrdup(_("(invalid type)"));
00905     } else {
00906         int anint = data.i64p[ix];
00907         char *t, *buf;
00908 
00909         t = buf = alloca(32);
00910         *t = '\0';
00911 
00912 #ifdef  NOTYET  /* XXX appending markers breaks :depflags format. */
00913         if (anint & RPMSENSE_SCRIPT_PRE)
00914             t = stpcpy(t, "(pre)");
00915         else if (anint & RPMSENSE_SCRIPT_POST)
00916             t = stpcpy(t, "(post)");
00917         else if (anint & RPMSENSE_SCRIPT_PREUN)
00918             t = stpcpy(t, "(preun)");
00919         else if (anint & RPMSENSE_SCRIPT_POSTUN)
00920             t = stpcpy(t, "(postun)");
00921 #endif
00922         if (anint & RPMSENSE_SENSEMASK)
00923             *t++ = ' ';
00924         if (anint & RPMSENSE_LESS)
00925             *t++ = '<';
00926         if (anint & RPMSENSE_GREATER)
00927             *t++ = '>';
00928         if (anint & RPMSENSE_EQUAL)
00929             *t++ = '=';
00930         if (anint & RPMSENSE_SENSEMASK)
00931             *t++ = ' ';
00932         *t = '\0';
00933 
00934         val = xstrdup(buf);
00935     }
00936 
00937     return val;
00938 }
00939 
00946 static int instprefixTag(Header h, HE_t he)
00947         /*@modifies he @*/
00948 {
00949     rpmTagType ipt;
00950     rpmTagData array;
00951 
00952     he->tag = RPMTAG_INSTALLPREFIX;
00953     if (headerGetEntry(h, RPMTAG_INSTALLPREFIX, (hTYP_t)&he->t, &he->p, &he->c)) {
00954         he->freeData = 0;
00955         return 0;
00956     }
00957     he->tag = RPMTAG_INSTPREFIXES;
00958     if (headerGetEntry(h, he->tag, (hTYP_t)&ipt, &array, &he->c)) {
00959         he->t = RPM_STRING_TYPE;
00960         he->c = 1;
00961         he->p.str = xstrdup(array.argv[0]);
00962         he->freeData = 1;
00963         array.ptr = headerFreeData(array.ptr, ipt);
00964         return 0;
00965     }
00966     return 1;
00967 }
00968 
00976 static int tv2uuidv1(Header h, HE_t he, struct timeval *tv)
00977         /*@modifies he @*/
00978 {
00979     uint64_t uuid_time = ((uint64_t)tv->tv_sec * 10000000) +
00980                         (tv->tv_usec * 10) + 0x01B21DD213814000ULL;
00981 
00982     he->t = RPM_BIN_TYPE;
00983     he->c = 128/8;
00984     he->p.ptr = xcalloc(1, he->c);
00985     he->freeData = 1;
00986     if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) {
00987         he->p.ptr = _free(he->p.ptr);
00988         he->freeData = 0;
00989         return 1;
00990     }
00991 
00992     he->p.ui8p[6] &= 0xf0;      /* preserve version, clear time_hi nibble */
00993     he->p.ui8p[8] &= 0x3f;      /* preserve reserved, clear clock */
00994     he->p.ui8p[9] &= 0x00;
00995 
00996     he->p.ui8p[3] = (uuid_time >>  0);
00997     he->p.ui8p[2] = (uuid_time >>  8);
00998     he->p.ui8p[1] = (uuid_time >> 16);
00999     he->p.ui8p[0] = (uuid_time >> 24);
01000     he->p.ui8p[5] = (uuid_time >> 32);
01001     he->p.ui8p[4] = (uuid_time >> 40);
01002     he->p.ui8p[6] |= (uuid_time >> 56) & 0x0f;
01003 
01004 #ifdef  NOTYET
01005     /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */
01006     he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f);
01007     he->p.ui8p[9] |= he->p.ui8p[3]
01008 #endif
01009 
01010     return 0;
01011 }
01012 
01019 static int tag2uuidv1(Header h, HE_t he)
01020         /*@modifies he @*/
01021 {
01022     struct timeval tv;
01023 
01024     if (!headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c))
01025         return 1;
01026     tv.tv_sec = he->p.ui32p[0];
01027     tv.tv_usec = (he->c > 1 ? he->p.ui32p[1] : 0);
01028     he->p.ptr = headerFreeData(he->p.ptr, he->t);
01029     return tv2uuidv1(h, he, &tv);
01030 }
01031 
01038 static int installtime_uuidTag(Header h, HE_t he)
01039         /*@modifies he @*/
01040 {
01041     he->tag = RPMTAG_INSTALLTIME;
01042     return tag2uuidv1(h, he);
01043 }
01044 
01051 static int buildtime_uuidTag(Header h, HE_t he)
01052         /*@modifies he @*/
01053 {
01054     he->tag = RPMTAG_BUILDTIME;
01055     return tag2uuidv1(h, he);
01056 }
01057 
01064 static int origintime_uuidTag(Header h, HE_t he)
01065         /*@modifies he @*/
01066 {
01067     he->tag = RPMTAG_ORIGINTIME;
01068     return tag2uuidv1(h, he);
01069 }
01070 
01077 static int installtid_uuidTag(Header h, HE_t he)
01078         /*@modifies he @*/
01079 {
01080     he->tag = RPMTAG_INSTALLTID;
01081     return tag2uuidv1(h, he);
01082 }
01083 
01090 static int removetid_uuidTag(Header h, HE_t he)
01091         /*@modifies he @*/
01092 {
01093     he->tag = RPMTAG_REMOVETID;
01094     return tag2uuidv1(h, he);
01095 }
01096 
01103 static int origintid_uuidTag(Header h, HE_t he)
01104         /*@modifies he @*/
01105 {
01106     he->tag = RPMTAG_ORIGINTID;
01107     return tag2uuidv1(h, he);
01108 }
01109 
01110 /*@unchecked@*/ /*@observer@*/
01111 static const char uuid_ns[] = "ns:URL";
01112 /*@unchecked@*/ /*@observer@*/
01113 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}";
01114 /*@unchecked@*/ /*@observer@*/
01115 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}";
01116 /*@unchecked@*/ /*@observer@*/
01117 static int uuid_version = 5;
01118 
01127 static int str2uuid(HE_t he, /*@null@*/ const char ** av,
01128                 int version, /*@null@*/ char * val)
01129         /*@modifies he @*/
01130 {
01131     const char * ns = NULL;
01132     const char * tagn = tagName(he->tag);
01133     const char * s = NULL;
01134     int rc;
01135 
01136     /* XXX Substitute Pkgid & Hdrid strings for aliases. */
01137     if (!strcmp("Sigmd5", tagn))
01138         tagn = "Pkgid";
01139     else if (!strcmp("Sha1header", tagn))
01140         tagn = "Hdrid";
01141 
01142     switch (version) {
01143     default:
01144         version = uuid_version;
01145         /*@fallthrough@*/
01146     case 3:
01147     case 5:
01148 assert(he->t == RPM_STRING_TYPE);
01149         ns = uuid_ns;
01150         s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/",
01151                         he->p.str, NULL);
01152         /*@fallthrough@*/
01153     case 4:
01154         break;
01155     }
01156     he->p.ptr = headerFreeData(he->p.ptr, he->t);
01157     he->t = RPM_BIN_TYPE;
01158     he->c = 128/8;
01159     he->p.ptr = xcalloc(1, he->c);
01160     he->freeData = 1;
01161     rc = rpmuuidMake(version, ns, s, val, (unsigned char *)he->p.ui8p);
01162     if (rc) {
01163         he->p.ptr = _free(he->p.ptr);
01164         he->freeData = 0;
01165     }
01166     s = _free(s);
01167     return rc;
01168 }
01169 
01176 static int tag2uuidv5(Header h, HE_t he)
01177         /*@modifies he @*/
01178 {
01179     if (!headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c))
01180         return 1;
01181     switch (he->t) {
01182     default:
01183 assert(0);
01184         /*@notreached@*/ break;
01185     case RPM_BIN_TYPE:  {       /* Convert RPMTAG_PKGID from binary => hex. */
01186         static const char hex[] = "0123456789abcdef";
01187         char * t;
01188         char * te;
01189         uint32_t i;
01190 
01191         t = te = xmalloc (2*he->c + 1);
01192         for (i = 0; i < he->c; i++) {
01193             *te++ = hex[ ((he->p.ui8p[i] >> 4) & 0x0f) ];
01194             *te++ = hex[ ((he->p.ui8p[i]     ) & 0x0f) ];
01195         }
01196         *te = '\0';
01197         he->p.ptr = headerFreeData(he->p.ptr, he->t);
01198         he->t = RPM_STRING_TYPE;
01199         he->p.ptr = t;
01200         he->c = 1;
01201         he->freeData = 1;
01202     }   break;
01203     case RPM_STRING_TYPE:
01204         break;
01205     }
01206     return str2uuid(he, NULL, 0, NULL);
01207 }
01208 
01215 static int pkguuidTag(Header h, HE_t he)
01216         /*@modifies he @*/
01217 {
01218     he->tag = RPMTAG_PKGID;
01219     return tag2uuidv5(h, he);
01220 }
01221 
01228 static int sourcepkguuidTag(Header h, HE_t he)
01229         /*@modifies he @*/
01230 {
01231     he->tag = RPMTAG_SOURCEPKGID;
01232     return tag2uuidv5(h, he);
01233 }
01234 
01241 static int hdruuidTag(Header h, HE_t he)
01242         /*@modifies he @*/
01243 {
01244     he->tag = RPMTAG_HDRID;
01245     return tag2uuidv5(h, he);
01246 }
01247 
01254 static int triggercondsTag(Header h, HE_t he)
01255         /*@modifies he @*/
01256 {
01257     HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
01258     rpmTagData flags;
01259     rpmTagData indices;
01260     rpmTagData names;
01261     rpmTagData versions;
01262     int numNames, numScripts;
01263     const char ** conds;
01264     rpmTagData s;
01265     char * item, * flagsStr;
01266     char * chptr;
01267     int i, j, xx;
01268 
01269     he->freeData = 0;
01270     xx = headerGetEntry(h, RPMTAG_TRIGGERNAME, NULL, &names, &numNames);
01271     if (!xx)
01272         return 0;
01273 
01274     _he->tag = he->tag;
01275     _he->t = RPM_INT32_TYPE;
01276     _he->p.i32p = NULL;
01277     _he->c = 1;
01278     _he->freeData = -1;
01279 
01280     xx = headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, &indices, NULL);
01281     xx = headerGetEntry(h, RPMTAG_TRIGGERFLAGS, NULL, &flags, NULL);
01282     xx = headerGetEntry(h, RPMTAG_TRIGGERVERSION, NULL, &versions, NULL);
01283     xx = headerGetEntry(h, RPMTAG_TRIGGERSCRIPTS, NULL, &s, &numScripts);
01284 
01285     he->t = RPM_STRING_ARRAY_TYPE;
01286     he->c = numScripts;
01287 
01288     he->freeData = 1;
01289     he->p.argv = conds = xmalloc(sizeof(*conds) * numScripts);
01290     for (i = 0; i < numScripts; i++) {
01291         chptr = xstrdup("");
01292 
01293         for (j = 0; j < numNames; j++) {
01294             if (indices.i32p[j] != i)
01295                 /*@innercontinue@*/ continue;
01296 
01297             item = xmalloc(strlen(names.argv[j]) + strlen(versions.argv[j]) + 20);
01298             if (flags.i32p[j] & RPMSENSE_SENSEMASK) {
01299                 _he->p.i32p = &flags.i32p[j];
01300                 flagsStr = depflagsFormat(_he, NULL);
01301                 sprintf(item, "%s %s %s", names.argv[j], flagsStr, versions.argv[j]);
01302                 flagsStr = _free(flagsStr);
01303             } else
01304                 strcpy(item, names.argv[j]);
01305 
01306             chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
01307             if (*chptr != '\0') strcat(chptr, ", ");
01308             strcat(chptr, item);
01309             item = _free(item);
01310         }
01311 
01312         conds[i] = chptr;
01313     }
01314 
01315     names.ptr = headerFreeData(names.ptr, -1);
01316     versions.ptr = headerFreeData(versions.ptr, -1);
01317     s.ptr = headerFreeData(s.ptr, -1);
01318 
01319     return 0;
01320 }
01321 
01328 static int triggertypeTag(Header h, HE_t he)
01329         /*@modifies he @*/
01330 {
01331     rpmTagData indices;
01332     rpmTagData flags;
01333     const char ** conds;
01334     rpmTagData s;
01335     int i, j, xx;
01336     int numScripts, numNames;
01337 
01338     he->freeData = 0;
01339     if (!headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, &indices, &numNames))
01340         return 1;
01341 
01342     xx = headerGetEntry(h, RPMTAG_TRIGGERFLAGS, NULL, &flags, NULL);
01343     xx = headerGetEntry(h, RPMTAG_TRIGGERSCRIPTS, NULL, &s, &numScripts);
01344 
01345     he->t = RPM_STRING_ARRAY_TYPE;
01346     he->c = numScripts;
01347 
01348     he->freeData = 1;
01349     he->p.argv = conds = xmalloc(sizeof(*conds) * numScripts);
01350     for (i = 0; i < numScripts; i++) {
01351         for (j = 0; j < numNames; j++) {
01352             if (indices.i32p[j] != i)
01353                 /*@innercontinue@*/ continue;
01354 
01355             if (flags.i32p[j] & RPMSENSE_TRIGGERPREIN)
01356                 conds[i] = xstrdup("prein");
01357             else if (flags.i32p[j] & RPMSENSE_TRIGGERIN)
01358                 conds[i] = xstrdup("in");
01359             else if (flags.i32p[j] & RPMSENSE_TRIGGERUN)
01360                 conds[i] = xstrdup("un");
01361             else if (flags.i32p[j] & RPMSENSE_TRIGGERPOSTUN)
01362                 conds[i] = xstrdup("postun");
01363             else
01364                 conds[i] = xstrdup("");
01365             /*@innerbreak@*/ break;
01366         }
01367     }
01368 
01369     s.ptr = headerFreeData(s.ptr, -1);
01370     return 0;
01371 }
01372 
01373 /* I18N look aside diversions */
01374 
01375 #if defined(ENABLE_NLS)
01376 /*@-exportlocal -exportheadervar@*/
01377 /*@unchecked@*/
01378 extern int _nl_msg_cat_cntr;    /* XXX GNU gettext voodoo */
01379 /*@=exportlocal =exportheadervar@*/
01380 #endif
01381 /*@observer@*/ /*@unchecked@*/
01382 static const char * language = "LANGUAGE";
01383 
01384 /*@observer@*/ /*@unchecked@*/
01385 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
01386 
01393 static int i18nTag(Header h, HE_t he)
01394         /*@globals rpmGlobalMacroContext, h_errno @*/
01395         /*@modifies he, rpmGlobalMacroContext @*/
01396 {
01397     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
01398     int rc = 1;         /* assume failure */
01399 
01400     he->t = RPM_STRING_TYPE;
01401     he->p.str = NULL;
01402     he->c = 0;
01403     he->freeData = 0;
01404 
01405     if (dstring && *dstring) {
01406         char *domain, *de;
01407         const char * langval;
01408         const char * msgkey;
01409         const char * msgid;
01410 
01411         {   const char * tn = tagName(he->tag);
01412             rpmTagData n = { .ptr = NULL };
01413             char * mk;
01414             size_t nb = sizeof("()");
01415             int xx = headerGetEntry(h, RPMTAG_NAME, NULL, &n, NULL);
01416             xx = 0;     /* XXX keep gcc quiet */
01417             if (tn)     nb += strlen(tn);
01418             if (n.str)  nb += strlen(n.str);
01419             mk = alloca(nb);
01420             sprintf(mk, "%s(%s)", (n.str ? n.str : ""), (tn ? tn : ""));
01421             msgkey = mk;
01422         }
01423 
01424         /* change to en_US for msgkey -> msgid resolution */
01425         langval = getenv(language);
01426         (void) setenv(language, "en_US", 1);
01427 #if defined(ENABLE_NLS)
01428 /*@i@*/ ++_nl_msg_cat_cntr;
01429 #endif
01430 
01431         msgid = NULL;
01432         for (domain = dstring; domain != NULL; domain = de) {
01433             de = strchr(domain, ':');
01434             if (de) *de++ = '\0';
01435             msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/;
01436             if (msgid != msgkey) break;
01437         }
01438 
01439         /* restore previous environment for msgid -> msgstr resolution */
01440         if (langval)
01441             (void) setenv(language, langval, 1);
01442         else
01443             unsetenv(language);
01444 #if defined(ENABLE_NLS)
01445 /*@i@*/ ++_nl_msg_cat_cntr;
01446 #endif
01447 
01448         if (domain && msgid) {
01449             const char * s = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/;
01450             if (s) {
01451                 rc = 0;
01452                 he->p.str = xstrdup(s);
01453                 he->c = 1;
01454                 he->freeData = 1;
01455             }
01456         }
01457     }
01458 
01459 /*@-dependenttrans@*/
01460     dstring = _free(dstring);
01461 /*@=dependenttrans@*/
01462     if (!rc)
01463         return rc;
01464 
01465     rc = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
01466     if (rc) {
01467         rc = 0;
01468         he->p.str = xstrdup(he->p.str);
01469         he->p.str = xstrtolocale(he->p.str);
01470         he->freeData = 1;
01471 /*@-nullstate@*/
01472         return rc;
01473 /*@=nullstate@*/
01474     }
01475 
01476     he->t = RPM_STRING_TYPE;
01477     he->p.str = NULL;
01478     he->c = 0;
01479     he->freeData = 0;
01480 
01481     return 1;
01482 }
01483 
01487 static int localeTag(Header h, HE_t he)
01488         /*@modifies he @*/
01489 {
01490     rpmTagType t;
01491     rpmTagData p;
01492     rpmTagCount c;
01493     const char ** argv;
01494     char * te;
01495     int rc;
01496 
01497     rc = headerGetEntry(h, he->tag, (hTYP_t)&t, &p, &c);
01498     if (!rc || p.ptr == NULL || c == 0) {
01499         he->t = RPM_STRING_TYPE;
01500         he->p.str = NULL;
01501         he->c = 0;
01502         he->freeData = 0;
01503         return 1;
01504     }
01505 
01506     if (t == RPM_STRING_TYPE) {
01507         p.str = xstrdup(p.str);
01508         p.str = xstrtolocale(p.str);
01509         he->freeData = 1;
01510     } else if (t == RPM_STRING_ARRAY_TYPE) {
01511         size_t l = 0;
01512         int i;
01513         for (i = 0; i < c; i++) {
01514             p.argv[i] = xstrdup(p.argv[i]);
01515             p.argv[i] = xstrtolocale(p.argv[i]);
01516 assert(p.argv[i] != NULL);
01517             l += strlen(p.argv[i]) + 1;
01518         }
01519         argv = xmalloc(c * sizeof(*argv) + l);
01520         te = (char *)&argv[c];
01521         for (i = 0; i < c; i++) {
01522             argv[i] = te;
01523             te = stpcpy(te, p.argv[i]);
01524             te++;
01525             p.argv[i] = _free(p.argv[i]);
01526         }
01527         p.ptr = _free(p.ptr);
01528         p.argv = argv;
01529         he->freeData = 1;
01530     } else
01531         he->freeData = 0;
01532 
01533     he->t = t;
01534     he->p.ptr = p.ptr;
01535     he->c = c;
01536     return 0;
01537 }
01538 
01545 static int summaryTag(Header h, HE_t he)
01546         /*@globals rpmGlobalMacroContext, h_errno @*/
01547         /*@modifies he, rpmGlobalMacroContext @*/
01548 {
01549     he->tag = RPMTAG_SUMMARY;
01550     return i18nTag(h, he);
01551 }
01552 
01559 static int descriptionTag(Header h, HE_t he)
01560         /*@globals rpmGlobalMacroContext, h_errno @*/
01561         /*@modifies he, rpmGlobalMacroContext @*/
01562 {
01563     he->tag = RPMTAG_DESCRIPTION;
01564     return i18nTag(h, he);
01565 }
01566 
01567 static int changelognameTag(Header h, HE_t he)
01568         /*@modifies he @*/
01569 {
01570     he->tag = RPMTAG_CHANGELOGNAME;
01571     return localeTag(h, he);
01572 }
01573 
01574 static int changelogtextTag(Header h, HE_t he)
01575         /*@modifies he @*/
01576 {
01577     he->tag = RPMTAG_CHANGELOGTEXT;
01578     return localeTag(h, he);
01579 }
01580 
01587 static int groupTag(Header h, HE_t he)
01588         /*@globals rpmGlobalMacroContext, h_errno @*/
01589         /*@modifies he, rpmGlobalMacroContext @*/
01590 {
01591     he->tag = RPMTAG_GROUP;
01592     return i18nTag(h, he);
01593 }
01594 
01601 /*@-globuse@*/
01602 static int dbinstanceTag(Header h, HE_t he)
01603         /*@globals rpmGlobalMacroContext, h_errno,
01604                 fileSystem, internalState @*/
01605         /*@modifies he, rpmGlobalMacroContext,
01606                 fileSystem, internalState @*/
01607 {
01608     he->tag = RPMTAG_DBINSTANCE;
01609     he->t = RPM_INT32_TYPE;
01610     he->p.i32p = xmalloc(sizeof(*he->p.i32p));
01611     he->p.i32p[0] = headerGetInstance(h);
01612     he->freeData = 1;
01613     he->c = 1;
01614     return 0;
01615 }
01616 /*@=globuse@*/
01617 
01624 /*@-globuse@*/
01625 static int headerstartoffTag(Header h, HE_t he)
01626         /*@globals rpmGlobalMacroContext, h_errno,
01627                 fileSystem, internalState @*/
01628         /*@modifies he, rpmGlobalMacroContext,
01629                 fileSystem, internalState @*/
01630 {
01631     he->tag = RPMTAG_HEADERSTARTOFF;
01632     he->t = RPM_INT64_TYPE;
01633     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
01634     he->p.ui64p[0] = headerGetStartOff(h);
01635     he->freeData = 1;
01636     he->c = 1;
01637     return 0;
01638 }
01639 /*@=globuse@*/
01640 
01647 /*@-globuse@*/
01648 static int headerendoffTag(Header h, HE_t he)
01649         /*@globals rpmGlobalMacroContext, h_errno,
01650                 fileSystem, internalState @*/
01651         /*@modifies he, rpmGlobalMacroContext,
01652                 fileSystem, internalState @*/
01653 {
01654     he->tag = RPMTAG_HEADERENDOFF;
01655     he->t = RPM_INT64_TYPE;
01656     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
01657     he->p.ui64p[0] = headerGetEndOff(h);
01658     he->freeData = 1;
01659     he->c = 1;
01660     return 0;
01661 }
01662 /*@=globuse@*/
01663 
01670 /*@-globuse@*/
01671 static int pkgoriginTag(Header h, HE_t he)
01672         /*@globals rpmGlobalMacroContext, h_errno,
01673                 fileSystem, internalState @*/
01674         /*@modifies he, rpmGlobalMacroContext,
01675                 fileSystem, internalState @*/
01676 {
01677     const char * origin;
01678 
01679     he->tag = RPMTAG_PACKAGEORIGIN;
01680     if (!headerGetEntry(h, he->tag, NULL, &origin, NULL)
01681      && (origin = headerGetOrigin(h)) != NULL)
01682     {
01683         he->t = RPM_STRING_TYPE;
01684         he->p.str = xstrdup(origin);
01685         he->c = 1;
01686         he->freeData = 1;
01687     }
01688     return 0;
01689 }
01690 /*@=globuse@*/
01691 
01698 /*@-globuse@*/
01699 static int pkgbaseurlTag(Header h, HE_t he)
01700         /*@globals rpmGlobalMacroContext, h_errno,
01701                 fileSystem, internalState @*/
01702         /*@modifies he, rpmGlobalMacroContext,
01703                 fileSystem, internalState @*/
01704 {
01705     const char * baseurl;
01706     int rc = 1;
01707 
01708     he->tag = RPMTAG_PACKAGEBASEURL;
01709     if (!headerGetEntry(h, he->tag, NULL, &baseurl, NULL)
01710      && (baseurl = headerGetBaseURL(h)) != NULL)
01711     {
01712         he->t = RPM_STRING_TYPE;
01713         he->p.str = xstrdup(baseurl);
01714         he->c = 1;
01715         he->freeData = 1;
01716         rc = 0;
01717     }
01718     return rc;
01719 }
01720 /*@=globuse@*/
01721 
01728 /*@-globuse@*/
01729 static int pkgdigestTag(Header h, HE_t he)
01730         /*@globals rpmGlobalMacroContext, h_errno,
01731                 fileSystem, internalState @*/
01732         /*@modifies he, rpmGlobalMacroContext,
01733                 fileSystem, internalState @*/
01734 {
01735     const char * digest;
01736     int rc = 1;
01737 
01738     he->tag = RPMTAG_PACKAGEDIGEST;
01739     if ((digest = headerGetDigest(h)) != NULL)
01740     {
01741         he->t = RPM_STRING_TYPE;
01742         he->p.str = xstrdup(digest);
01743         he->c = 1;
01744         he->freeData = 1;
01745         rc = 0;
01746     }
01747     return rc;
01748 }
01749 /*@=globuse@*/
01750 
01757 /*@-globuse@*/
01758 static int pkgmtimeTag(Header h, HE_t he)
01759         /*@globals rpmGlobalMacroContext, h_errno,
01760                 fileSystem, internalState @*/
01761         /*@modifies he, rpmGlobalMacroContext,
01762                 fileSystem, internalState @*/
01763 {
01764     struct stat * st = headerGetStatbuf(h);
01765     he->tag = RPMTAG_PACKAGETIME;
01766     he->t = RPM_UINT64_TYPE;
01767     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
01768     he->p.ui64p[0] = st->st_mtime;
01769     he->freeData = 1;
01770     he->c = 1;
01771     return 0;
01772 }
01773 /*@=globuse@*/
01774 
01781 /*@-globuse@*/
01782 static int pkgsizeTag(Header h, HE_t he)
01783         /*@globals rpmGlobalMacroContext, h_errno,
01784                 fileSystem, internalState @*/
01785         /*@modifies he, rpmGlobalMacroContext,
01786                 fileSystem, internalState @*/
01787 {
01788     struct stat * st = headerGetStatbuf(h);
01789     he->tag = RPMTAG_PACKAGESIZE;
01790     he->t = RPM_UINT64_TYPE;
01791     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
01792     he->p.ui64p[0] = st->st_size;
01793     he->freeData = 1;
01794     he->c = 1;
01795     return 0;
01796 }
01797 /*@=globuse@*/
01798 
01804 /*@only@*/
01805 static char * hGetNVRA(Header h)
01806         /*@modifies h @*/
01807 {
01808     const char * N = NULL;
01809     const char * V = NULL;
01810     const char * R = NULL;
01811     const char * A = NULL;
01812     size_t nb = 0;
01813     char * NVRA, * t;
01814 
01815     (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
01816     if (N)      nb += strlen(N);
01817     if (V)      nb += strlen(V) + 1;
01818     if (R)      nb += strlen(R) + 1;
01819     if (A)      nb += strlen(A) + 1;
01820     nb++;
01821     NVRA = t = xmalloc(nb);
01822     *t = '\0';
01823     if (N)      t = stpcpy(t, N);
01824     if (V)      t = stpcpy( stpcpy(t, "-"), V);
01825     if (R)      t = stpcpy( stpcpy(t, "-"), R);
01826     if (A)      t = stpcpy( stpcpy(t, "."), A);
01827     return NVRA;
01828 }
01829 
01836 /*@-globuse@*/
01837 static int nvraTag(Header h, HE_t he)
01838         /*@globals rpmGlobalMacroContext, h_errno,
01839                 fileSystem, internalState @*/
01840         /*@modifies h, he, rpmGlobalMacroContext,
01841                 fileSystem, internalState @*/
01842 {
01843     he->t = RPM_STRING_TYPE;
01844     he->p.str = hGetNVRA(h);
01845     he->c = 1;
01846     he->freeData = 1;
01847     return 0;
01848 }
01849 /*@=globuse@*/
01850 
01857 static int _fnTag(Header h, HE_t he)
01858         /*@modifies he @*/
01859 {
01860     he->t = RPM_STRING_ARRAY_TYPE;
01861     rpmfiBuildFNames(h, he->tag, &he->p.argv, &he->c);
01862     he->freeData = 1;
01863     return 0;
01864 }
01865 
01866 static int filepathsTag(Header h, HE_t he)
01867         /*@modifies he @*/
01868 {
01869     he->tag = RPMTAG_BASENAMES;
01870     return _fnTag(h, he);
01871 }
01872 
01873 static int origpathsTag(Header h, HE_t he)
01874         /*@modifies he @*/
01875 {
01876     he->tag = RPMTAG_ORIGBASENAMES;
01877     return _fnTag(h, he);
01878 }
01879 
01886 static int fsnamesTag( /*@unused@*/ Header h, HE_t he)
01887         /*@globals fileSystem, internalState @*/
01888         /*@modifies he, fileSystem, internalState @*/
01889 {
01890     const char ** list;
01891 
01892     if (rpmGetFilesystemList(&list, &he->c))
01893         return 1;
01894 
01895     he->t = RPM_STRING_ARRAY_TYPE;
01896     he->p.argv = list;
01897     he->freeData = 0;
01898 
01899     return 0;
01900 }
01901 
01908 static int fssizesTag(Header h, HE_t he)
01909         /*@globals rpmGlobalMacroContext, h_errno,
01910                 fileSystem, internalState @*/
01911         /*@modifies he, rpmGlobalMacroContext,
01912                 fileSystem, internalState @*/
01913 {
01914     HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
01915     const char ** fnames;
01916     uint_64 * usages;
01917     int numFiles;
01918     int rc = 1;         /* assume error */
01919     int xx;
01920 
01921     vhe->tag = RPMTAG_FILESIZES;
01922     xx = headerGetEntry(h, vhe->tag, (hTYP_t)&vhe->t, &vhe->p.ptr, &vhe->c);
01923     if (!xx) {
01924         numFiles = 0;
01925         fnames = NULL;
01926     } else
01927         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fnames, &numFiles);
01928 
01929     if (rpmGetFilesystemList(NULL, &he->c))
01930         goto exit;
01931 
01932     he->t = RPM_INT64_TYPE;
01933     he->freeData = 1;
01934 
01935     if (fnames == NULL)
01936         he->p.ui64p = xcalloc(he->c, sizeof(*usages));
01937     else
01938     if (rpmGetFilesystemUsage(fnames, vhe->p.ui32p, numFiles, &he->p.ui64p, 0)) 
01939         goto exit;
01940 
01941     rc = 0;
01942 
01943 exit:
01944     fnames = _free(fnames);
01945 
01946     return rc;
01947 }
01948 
01955 static int fileclassTag(Header h, HE_t he)
01956         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01957         /*@modifies h, he,
01958                 rpmGlobalMacroContext, fileSystem, internalState @*/
01959 {
01960     he->t = RPM_STRING_ARRAY_TYPE;
01961     rpmfiBuildFClasses(h, &he->p.argv, &he->c);
01962     he->freeData = 1;
01963     return 0;
01964 }
01965 
01972 static int filecontextsTag(Header h, HE_t he)
01973         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01974         /*@modifies h, he,
01975                 rpmGlobalMacroContext, fileSystem, internalState @*/
01976 {
01977     he->t = RPM_STRING_ARRAY_TYPE;
01978     rpmfiBuildFContexts(h, &he->p.argv, &he->c);
01979     he->freeData = 1;
01980     return 0;
01981 }
01982 
01989 static int fscontextsTag(Header h, HE_t he)
01990         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01991         /*@modifies h, he,
01992                 rpmGlobalMacroContext, fileSystem, internalState @*/
01993 {
01994     he->t = RPM_STRING_ARRAY_TYPE;
01995     rpmfiBuildFSContexts(h, &he->p.argv, &he->c);
01996     he->freeData = 1;
01997     return 0;
01998 }
01999 
02006 static int recontextsTag(Header h, HE_t he)
02007         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02008         /*@modifies h, he,
02009                 rpmGlobalMacroContext, fileSystem, internalState @*/
02010 {
02011     he->t = RPM_STRING_ARRAY_TYPE;
02012     rpmfiBuildREContexts(h, &he->p.argv, &he->c);
02013     he->freeData = 1;
02014     return 0;
02015 }
02016 
02023 static int fileprovideTag(Header h, HE_t he)
02024         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02025         /*@modifies h, he,
02026                 rpmGlobalMacroContext, fileSystem, internalState @*/
02027 {
02028     he->t = RPM_STRING_ARRAY_TYPE;
02029     rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, &he->p.argv, &he->c);
02030     he->freeData = 1;
02031     return 0;
02032 }
02033 
02040 static int filerequireTag(Header h, HE_t he)
02041         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02042         /*@modifies h, he,
02043                 rpmGlobalMacroContext, fileSystem, internalState @*/
02044 {
02045     he->t = RPM_STRING_ARRAY_TYPE;
02046     rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, &he->p.argv, &he->c);
02047     he->freeData = 1;
02048     return 0;
02049 }
02050 
02057 static int missingokTag(Header h, HE_t he)
02058         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02059         /*@modifies h, he,
02060                 rpmGlobalMacroContext, fileSystem, internalState @*/
02061 {
02062     rpmds ds = rpmdsNew(h, RPMTAG_REQUIRENAME, 0);
02063     ARGV_t av = NULL;
02064     ARGV_t argv;
02065     int argc = 0;
02066     char * t;
02067     size_t nb = 0;
02068     int i;
02069 
02070 assert(ds != NULL);
02071     /* Collect dependencies marked as hints. */
02072     ds = rpmdsInit(ds);
02073     if (ds != NULL)
02074     while (rpmdsNext(ds) >= 0) {
02075         int Flags = rpmdsFlags(ds);
02076         const char * DNEVR;
02077         if (!(Flags & RPMSENSE_MISSINGOK))
02078             continue;
02079         DNEVR = rpmdsDNEVR(ds);
02080         if (DNEVR == NULL)
02081             continue;
02082         nb += sizeof(*argv) + strlen(DNEVR+2) + 1;
02083         (void) argvAdd(&av, DNEVR+2);
02084         argc++;
02085     }
02086     nb += sizeof(*argv);        /* final argv NULL */
02087 
02088     /* Create contiguous header string array. */
02089     argv = (ARGV_t) xcalloc(nb, 1);
02090     t = (char *)(argv + argc);
02091     for (i = 0; i < argc; i++) {
02092         argv[i] = t;
02093         t = stpcpy(t, av[i]);
02094         *t++ = '\0';
02095     }
02096     av = argvFree(av);
02097     ds = rpmdsFree(ds);
02098 
02099     /* XXX perhaps return "(none)" inband if no suggests/enhances <shrug>. */
02100 
02101     he->t = RPM_STRING_ARRAY_TYPE;
02102     he->p.argv = argv;
02103     he->c = argc;
02104     he->freeData = 1;
02105     return 0;
02106 }
02107 
02108 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F,
02109                 uint32_t i)
02110         /*@*/
02111 {
02112     int a = -2, b = -2;
02113 
02114     if (N.argv[i] == NULL || *N.argv[i] == '\0')
02115         return 1;
02116     if (tag == RPMTAG_REQUIRENAME && i > 0
02117      && !(a=strcmp(N.argv[i], N.argv[i-1]))
02118      && !(b=strcmp(EVR.argv[i], EVR.argv[i-1]))
02119      && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e)))
02120         return 1;
02121     return 0;
02122 }
02123 
02124 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
02125         /*@modifies he @*/
02126 {
02127     rpmTag tag = he->tag;
02128     rpmTagData N = { .ptr = NULL };
02129     rpmTagData EVR = { .ptr = NULL };
02130     rpmTagData F = { .ptr = NULL };
02131     size_t nb;
02132     uint32_t ac;
02133     uint32_t c;
02134     uint32_t i;
02135     char *t;
02136     int rc = 1;         /* assume failure */
02137     int xx;
02138 
02139     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02140     if (xx == 0) goto exit;
02141     N.argv = he->p.argv;
02142     c = he->c;
02143 
02144     he->tag = EVRtag;
02145     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02146     if (xx == 0) goto exit;
02147     EVR.argv = he->p.argv;
02148 
02149     he->tag = Ftag;
02150     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02151     if (xx == 0) goto exit;
02152     F.ui32p = he->p.ui32p;
02153 
02154     nb = sizeof(*he->p.argv);
02155     ac = 0;
02156     for (i = 0; i < c; i++) {
02157         if (PRCOSkip(tag, N, EVR, F, i))
02158             continue;
02159         ac++;
02160         nb += sizeof(*he->p.argv);
02161         nb += sizeof("<rpm:entry name=\"\"/>");
02162         if (*N.argv[i] == '/')
02163             nb += xmlstrlen(N.argv[i]);
02164         else
02165             nb += strlen(N.argv[i]);
02166         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
02167             nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1;
02168             nb += strlen(EVR.argv[i]);
02169             if (strchr(EVR.argv[i], ':') != NULL)
02170                 nb -= 2;
02171             if (strchr(EVR.argv[i], '-') != NULL)
02172                 nb += sizeof(" rel=\"\"") - 2;
02173         }
02174 #ifdef  NOTNOW
02175         if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
02176             nb += sizeof(" pre=\"1\"") - 1;
02177 #endif
02178     }
02179 
02180     he->t = RPM_STRING_ARRAY_TYPE;
02181     he->c = ac;
02182     he->freeData = 1;
02183     he->p.argv = xmalloc(nb + BUFSIZ);  /* XXX hack: leave slop */
02184     t = (char *) &he->p.argv[he->c + 1];
02185     ac = 0;
02186     for (i = 0; i < c; i++) {
02187         if (PRCOSkip(tag, N, EVR, F, i))
02188             continue;
02189         he->p.argv[ac++] = t;
02190         t = stpcpy(t, "<rpm:entry");
02191         t = stpcpy(t, " name=\"");
02192         if (*N.argv[i] == '/') {
02193             t = xmlstrcpy(t, N.argv[i]);        t += strlen(t);
02194         } else
02195             t = stpcpy(t, N.argv[i]);
02196         t = stpcpy(t, "\"");
02197         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
02198             static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
02199             int Fx = ((F.ui32p[i] >> 1) & 0x7);
02200             const char *E, *V, *R;
02201             char *f, *fe;
02202             t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\"");
02203             f = (char *) EVR.argv[i];
02204             for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++);
02205             if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
02206             V = f;
02207             for (fe = f; *fe != '\0' && *fe != '-'; fe++);
02208             if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
02209             t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\"");
02210             t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\"");
02211             if (R != NULL)
02212                 t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\"");
02213         }
02214 #ifdef  NOTNOW
02215         if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
02216             t = stpcpy(t, " pre=\"1\"");
02217 #endif
02218         t = stpcpy(t, "/>");
02219         *t++ = '\0';
02220     }
02221     he->p.argv[he->c] = NULL;
02222     rc = 0;
02223 
02224 exit:
02225     N.argv = _free(N.argv);
02226     EVR.argv = _free(EVR.argv);
02227     return rc;
02228 }
02229 
02230 static int PxmlTag(Header h, HE_t he)
02231         /*@modifies he @*/
02232 {
02233     he->tag = RPMTAG_PROVIDENAME;
02234     return PRCOxmlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
02235 }
02236 
02237 static int RxmlTag(Header h, HE_t he)
02238         /*@modifies he @*/
02239 {
02240     he->tag = RPMTAG_REQUIRENAME;
02241     return PRCOxmlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
02242 }
02243 
02244 static int CxmlTag(Header h, HE_t he)
02245         /*@modifies he @*/
02246 {
02247     he->tag = RPMTAG_CONFLICTNAME;
02248     return PRCOxmlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
02249 }
02250 
02251 static int OxmlTag(Header h, HE_t he)
02252         /*@modifies he @*/
02253 {
02254     he->tag = RPMTAG_OBSOLETENAME;
02255     return PRCOxmlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
02256 }
02257 
02263 static size_t sqlstrlen(const char * s)
02264         /*@*/
02265 {
02266     size_t len = 0;
02267     int c;
02268 
02269     while ((c = (int) *s++) != (int) '\0')
02270     {
02271         switch (c) {
02272         case '\'':      len += 1;                       /*@fallthrough@*/
02273         default:        len += 1;                       /*@switchbreak@*/ break;
02274         }
02275     }
02276     return len;
02277 }
02278 
02285 static char * sqlstrcpy(/*@returned@*/ char * t, const char * s)
02286         /*@modifies t @*/
02287 {
02288     char * te = t;
02289     int c;
02290 
02291     while ((c = (int) *s++) != (int) '\0') {
02292         switch (c) {
02293         case '\'':      *te++ = (char) c;               /*@fallthrough@*/
02294         default:        *te++ = (char) c;               /*@switchbreak@*/ break;
02295         }
02296     }
02297     *te = '\0';
02298     return t;
02299 }
02300 
02307 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av)
02308         /*@*/
02309 {
02310     int ix = (he->ix > 0 ? he->ix : 0);
02311     char * val;
02312 
02313 assert(ix == 0);
02314     if (he->t != RPM_STRING_TYPE) {
02315         val = xstrdup(_("(not a string)"));
02316     } else {
02317         const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
02318         size_t nb = sqlstrlen(s);
02319         char * t;
02320 
02321         val = t = xcalloc(1, nb + 1);
02322         t = sqlstrcpy(t, s);    t += strlen(t);
02323         *t = '\0';
02324         s = _free(s);
02325     }
02326 
02327 /*@-globstate@*/
02328     return val;
02329 /*@=globstate@*/
02330 }
02331 
02332 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
02333         /*@modifies he @*/
02334 {
02335     rpmTag tag = he->tag;
02336     rpmTagData N = { .ptr = NULL };
02337     rpmTagData EVR = { .ptr = NULL };
02338     rpmTagData F = { .ptr = NULL };
02339     char instance[64];
02340     size_t nb;
02341     uint32_t ac;
02342     uint32_t c;
02343     uint32_t i;
02344     char *t;
02345     int rc = 1;         /* assume failure */
02346     int xx;
02347 
02348     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02349     if (xx == 0) goto exit;
02350     N.argv = he->p.argv;
02351     c = he->c;
02352 
02353     he->tag = EVRtag;
02354     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02355     if (xx == 0) goto exit;
02356     EVR.argv = he->p.argv;
02357 
02358     he->tag = Ftag;
02359     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02360     if (xx == 0) goto exit;
02361     F.ui32p = he->p.ui32p;
02362 
02363     xx = snprintf(instance, sizeof(instance), "'%d'", headerGetInstance(h));
02364     nb = sizeof(*he->p.argv);
02365     ac = 0;
02366     for (i = 0; i < c; i++) {
02367         if (PRCOSkip(tag, N, EVR, F, i))
02368             continue;
02369         ac++;
02370         nb += sizeof(*he->p.argv);
02371         nb += strlen(instance) + sizeof(", '', '', '', '', ''");
02372         if (tag == RPMTAG_REQUIRENAME)
02373             nb += sizeof(", ''") - 1;
02374         nb += strlen(N.argv[i]);
02375         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
02376             nb += strlen(EVR.argv[i]);
02377             nb += sizeof("EQ0") - 1;
02378         }
02379 #ifdef  NOTNOW
02380         if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
02381             nb += sizeof("1") - 1;
02382 #endif
02383     }
02384 
02385     he->t = RPM_STRING_ARRAY_TYPE;
02386     he->c = ac;
02387     he->freeData = 1;
02388     he->p.argv = xmalloc(nb + BUFSIZ);  /* XXX hack: leave slop */
02389     t = (char *) &he->p.argv[he->c + 1];
02390     ac = 0;
02391     for (i = 0; i < c; i++) {
02392         if (PRCOSkip(tag, N, EVR, F, i))
02393             continue;
02394         he->p.argv[ac++] = t;
02395         t = stpcpy(t, instance);
02396         t = stpcpy( stpcpy( stpcpy(t, ", '"), N.argv[i]), "'");
02397         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
02398             static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
02399             int Fx = ((F.ui32p[i] >> 1) & 0x7);
02400             const char *E, *V, *R;
02401             char *f, *fe;
02402             t = stpcpy( stpcpy( stpcpy(t, ", '"), Fstr[Fx]), "'");
02403             f = (char *) EVR.argv[i];
02404             for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++);
02405             if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
02406             V = f;
02407             for (fe = f; *fe != '\0' && *fe != '-'; fe++);
02408             if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
02409             t = stpcpy( stpcpy( stpcpy(t, ", '"), (E && *E ? E : "0")), "'");
02410             t = stpcpy( stpcpy( stpcpy(t, ", '"), V), "'");
02411             t = stpcpy( stpcpy( stpcpy(t, ", '"), (R ? R : "")), "'");
02412         } else
02413             t = stpcpy(t, ", '', '', '', ''");
02414 #ifdef  NOTNOW
02415         if (tag == RPMTAG_REQUIRENAME)
02416             t = stpcpy(stpcpy(stpcpy(t, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'");
02417 #endif
02418         *t++ = '\0';
02419     }
02420     he->p.argv[he->c] = NULL;
02421     rc = 0;
02422 
02423 exit:
02424     N.argv = _free(N.argv);
02425     EVR.argv = _free(EVR.argv);
02426     return rc;
02427 }
02428 
02429 static int PsqlTag(Header h, HE_t he)
02430         /*@modifies he @*/
02431 {
02432     he->tag = RPMTAG_PROVIDENAME;
02433     return PRCOsqlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
02434 }
02435 
02436 static int RsqlTag(Header h, HE_t he)
02437         /*@modifies he @*/
02438 {
02439     he->tag = RPMTAG_REQUIRENAME;
02440     return PRCOsqlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
02441 }
02442 
02443 static int CsqlTag(Header h, HE_t he)
02444         /*@modifies he @*/
02445 {
02446     he->tag = RPMTAG_CONFLICTNAME;
02447     return PRCOsqlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
02448 }
02449 
02450 static int OsqlTag(Header h, HE_t he)
02451         /*@modifies he @*/
02452 {
02453     he->tag = RPMTAG_OBSOLETENAME;
02454     return PRCOsqlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
02455 }
02456 
02457 static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, uint32_t i)
02458         /*@*/
02459 {
02460     const char * dn = DN.argv[DI.ui32p[i]];
02461     size_t dnlen = strlen(dn);
02462 
02463     if (strstr(dn, "bin/") != NULL)
02464         return 1;
02465     if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen))
02466         return 1;
02467     if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail"))
02468         return 1;
02469     return 2;
02470 }
02471 
02472 static int FDGxmlTag(Header h, HE_t he, int lvl)
02473         /*@modifies he @*/
02474 {
02475     rpmTagData BN = { .ptr = NULL };
02476     rpmTagData DN = { .ptr = NULL };
02477     rpmTagData DI = { .ptr = NULL };
02478     rpmTagData FMODES = { .ptr = NULL };
02479     rpmTagData FFLAGS = { .ptr = NULL };
02480     size_t nb;
02481     uint32_t ac;
02482     uint32_t c;
02483     uint32_t i;
02484     char *t;
02485     int rc = 1;         /* assume failure */
02486     int xx;
02487 
02488     he->tag = RPMTAG_BASENAMES;
02489     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02490     if (xx == 0) goto exit;
02491     BN.argv = he->p.argv;
02492     c = he->c;
02493 
02494     he->tag = RPMTAG_DIRNAMES;
02495     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02496     if (xx == 0) goto exit;
02497     DN.argv = he->p.argv;
02498 
02499     he->tag = RPMTAG_DIRINDEXES;
02500     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02501     if (xx == 0) goto exit;
02502     DI.ui32p = he->p.ui32p;
02503 
02504     he->tag = RPMTAG_FILEMODES;
02505     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02506     if (xx == 0) goto exit;
02507     FMODES.ui16p = he->p.ui16p;
02508 
02509     he->tag = RPMTAG_FILEFLAGS;
02510     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02511     if (xx == 0) goto exit;
02512     FFLAGS.ui32p = he->p.ui32p;
02513 
02514     nb = sizeof(*he->p.argv);
02515     ac = 0;
02516     for (i = 0; i < c; i++) {
02517         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02518             continue;
02519         ac++;
02520         nb += sizeof(*he->p.argv);
02521         nb += sizeof("<file></file>");
02522         nb += xmlstrlen(DN.argv[DI.ui32p[i]]);
02523         nb += xmlstrlen(BN.argv[i]);
02524         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
02525             nb += sizeof(" type=\"ghost\"") - 1;
02526         else if (S_ISDIR(FMODES.ui16p[i]))
02527             nb += sizeof(" type=\"dir\"") - 1;
02528     }
02529 
02530     he->t = RPM_STRING_ARRAY_TYPE;
02531     he->c = ac;
02532     he->freeData = 1;
02533     he->p.argv = xmalloc(nb);
02534     t = (char *) &he->p.argv[he->c + 1];
02535     ac = 0;
02536     /* FIXME: Files, then dirs, finally ghosts breaks sort order.  */
02537     for (i = 0; i < c; i++) {
02538         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02539             continue;
02540         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
02541             continue;
02542         if (S_ISDIR(FMODES.ui16p[i]))
02543             continue;
02544         he->p.argv[ac++] = t;
02545         t = stpcpy(t, "<file>");
02546         t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
02547         t = xmlstrcpy(t, BN.argv[i]);           t += strlen(t);
02548         t = stpcpy(t, "</file>");
02549         *t++ = '\0';
02550     }
02551     for (i = 0; i < c; i++) {
02552         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02553             continue;
02554         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
02555             continue;
02556         if (!S_ISDIR(FMODES.ui16p[i]))
02557             continue;
02558         he->p.argv[ac++] = t;
02559         t = stpcpy(t, "<file type=\"dir\">");
02560         t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
02561         t = xmlstrcpy(t, BN.argv[i]);           t += strlen(t);
02562         t = stpcpy(t, "</file>");
02563         *t++ = '\0';
02564     }
02565     for (i = 0; i < c; i++) {
02566         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02567             continue;
02568         if (!(FFLAGS.ui32p[i] & 0x40))  /* XXX RPMFILE_GHOST */
02569             continue;
02570         he->p.argv[ac++] = t;
02571         t = stpcpy(t, "<file type=\"ghost\">");
02572         t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
02573         t = xmlstrcpy(t, BN.argv[i]);           t += strlen(t);
02574         t = stpcpy(t, "</file>");
02575         *t++ = '\0';
02576     }
02577 
02578     he->p.argv[he->c] = NULL;
02579     rc = 0;
02580 
02581 exit:
02582     BN.argv = _free(BN.argv);
02583     DN.argv = _free(DN.argv);
02584     return rc;
02585 }
02586 
02587 static int F1xmlTag(Header h, HE_t he)
02588         /*@modifies he @*/
02589 {
02590     he->tag = RPMTAG_BASENAMES;
02591     return FDGxmlTag(h, he, 1);
02592 }
02593 
02594 static int F2xmlTag(Header h, HE_t he)
02595         /*@modifies he @*/
02596 {
02597     he->tag = RPMTAG_BASENAMES;
02598     return FDGxmlTag(h, he, 2);
02599 }
02600 
02601 static int FDGsqlTag(Header h, HE_t he, int lvl)
02602         /*@modifies he @*/
02603 {
02604     rpmTagData BN = { .ptr = NULL };
02605     rpmTagData DN = { .ptr = NULL };
02606     rpmTagData DI = { .ptr = NULL };
02607     rpmTagData FMODES = { .ptr = NULL };
02608     rpmTagData FFLAGS = { .ptr = NULL };
02609     char instance[64];
02610     size_t nb;
02611     uint32_t ac;
02612     uint32_t c;
02613     uint32_t i;
02614     char *t;
02615     int rc = 1;         /* assume failure */
02616     int xx;
02617 
02618     he->tag = RPMTAG_BASENAMES;
02619     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02620     if (xx == 0) goto exit;
02621     BN.argv = he->p.argv;
02622     c = he->c;
02623 
02624     he->tag = RPMTAG_DIRNAMES;
02625     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02626     if (xx == 0) goto exit;
02627     DN.argv = he->p.argv;
02628 
02629     he->tag = RPMTAG_DIRINDEXES;
02630     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02631     if (xx == 0) goto exit;
02632     DI.ui32p = he->p.ui32p;
02633 
02634     he->tag = RPMTAG_FILEMODES;
02635     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02636     if (xx == 0) goto exit;
02637     FMODES.ui16p = he->p.ui16p;
02638 
02639     he->tag = RPMTAG_FILEFLAGS;
02640     xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
02641     if (xx == 0) goto exit;
02642     FFLAGS.ui32p = he->p.ui32p;
02643 
02644     xx = snprintf(instance, sizeof(instance), "'%d'", headerGetInstance(h));
02645     nb = sizeof(*he->p.argv);
02646     ac = 0;
02647     for (i = 0; i < c; i++) {
02648         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02649             continue;
02650         ac++;
02651         nb += sizeof(*he->p.argv);
02652         nb += strlen(instance) + sizeof(", '', ''");
02653         nb += strlen(DN.argv[DI.ui32p[i]]);
02654         nb += strlen(BN.argv[i]);
02655         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
02656             nb += sizeof("ghost") - 1;
02657         else if (S_ISDIR(FMODES.ui16p[i]))
02658             nb += sizeof("dir") - 1;
02659         else
02660             nb += sizeof("file") - 1;
02661     }
02662 
02663     he->t = RPM_STRING_ARRAY_TYPE;
02664     he->c = ac;
02665     he->freeData = 1;
02666     he->p.argv = xmalloc(nb);
02667     t = (char *) &he->p.argv[he->c + 1];
02668     ac = 0;
02669     /* FIXME: Files, then dirs, finally ghosts breaks sort order.  */
02670     for (i = 0; i < c; i++) {
02671         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02672             continue;
02673         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
02674             continue;
02675         if (S_ISDIR(FMODES.ui16p[i]))
02676             continue;
02677         he->p.argv[ac++] = t;
02678         t = stpcpy( stpcpy(t, instance), ", '");
02679         t = strcpy(t, DN.argv[DI.ui32p[i]]);    t += strlen(t);
02680         t = strcpy(t, BN.argv[i]);              t += strlen(t);
02681         t = stpcpy(t, "', 'file'");
02682         *t++ = '\0';
02683     }
02684     for (i = 0; i < c; i++) {
02685         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02686             continue;
02687         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
02688             continue;
02689         if (!S_ISDIR(FMODES.ui16p[i]))
02690             continue;
02691         he->p.argv[ac++] = t;
02692         t = stpcpy( stpcpy(t, instance), ", '");
02693         t = strcpy(t, DN.argv[DI.ui32p[i]]);    t += strlen(t);
02694         t = strcpy(t, BN.argv[i]);              t += strlen(t);
02695         t = stpcpy(t, "', 'dir'");
02696         *t++ = '\0';
02697     }
02698     for (i = 0; i < c; i++) {
02699         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
02700             continue;
02701         if (!(FFLAGS.ui32p[i] & 0x40))  /* XXX RPMFILE_GHOST */
02702             continue;
02703         he->p.argv[ac++] = t;
02704         t = stpcpy( stpcpy(t, instance), ", '");
02705         t = strcpy(t, DN.argv[DI.ui32p[i]]);    t += strlen(t);
02706         t = strcpy(t, BN.argv[i]);              t += strlen(t);
02707         t = stpcpy(t, "', 'ghost'");
02708         *t++ = '\0';
02709     }
02710 
02711     he->p.argv[he->c] = NULL;
02712     rc = 0;
02713 
02714 exit:
02715     BN.argv = _free(BN.argv);
02716     DN.argv = _free(DN.argv);
02717     return rc;
02718 }
02719 
02720 static int F1sqlTag(Header h, HE_t he)
02721         /*@modifies he @*/
02722 {
02723     he->tag = RPMTAG_BASENAMES;
02724     return FDGsqlTag(h, he, 1);
02725 }
02726 
02727 static int F2sqlTag(Header h, HE_t he)
02728         /*@modifies he @*/
02729 {
02730     he->tag = RPMTAG_BASENAMES;
02731     return FDGsqlTag(h, he, 2);
02732 }
02733 
02740 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av)
02741         /*@*/
02742 {
02743     char * val;
02744 
02745     if (he->t != RPM_STRING_TYPE) {
02746         val = xstrdup(_("(not a string)"));
02747     } else {
02748         const char * bn;
02749         const char * s;
02750         size_t nb;
02751         char * t;
02752 
02753         /* Get rightmost '/' in string (i.e. basename(3) behavior). */
02754         if ((bn = strrchr(he->p.str, '/')) != NULL)
02755             bn++;
02756         else
02757             bn = he->p.str;
02758 
02759         /* Convert to utf8, escape for XML CDATA. */
02760         s = strdup_locale_convert(bn, (av ? av[0] : NULL));
02761         nb = xmlstrlen(s);
02762         val = t = xcalloc(1, nb + 1);
02763         t = xmlstrcpy(t, s);    t += strlen(t);
02764         *t = '\0';
02765         s = _free(s);
02766     }
02767 
02768 /*@-globstate@*/
02769     return val;
02770 /*@=globstate@*/
02771 }
02772 
02773 typedef struct key_s {
02774 /*@observer@*/
02775         const char *name;               /* key name */
02776         uint32_t value;
02777 } KEY;
02778 
02779 /*@unchecked@*/ /*@observer@*/
02780 static KEY keyDigests[] = {
02781     { "adler32",        PGPHASHALGO_ADLER32 },
02782     { "crc32",          PGPHASHALGO_CRC32 },
02783     { "crc64",          PGPHASHALGO_CRC64 },
02784     { "haval160",       PGPHASHALGO_HAVAL_5_160 },
02785     { "jlu32",          PGPHASHALGO_JLU32 },
02786     { "md2",            PGPHASHALGO_MD2 },
02787     { "md4",            PGPHASHALGO_MD4 },
02788     { "md5",            PGPHASHALGO_MD5 },
02789     { "rmd128",         PGPHASHALGO_RIPEMD128 },
02790     { "rmd160",         PGPHASHALGO_RIPEMD160 },
02791     { "rmd256",         PGPHASHALGO_RIPEMD256 },
02792     { "rmd320",         PGPHASHALGO_RIPEMD320 },
02793     { "salsa10",        PGPHASHALGO_SALSA10 },
02794     { "salsa20",        PGPHASHALGO_SALSA20 },
02795     { "sha1",           PGPHASHALGO_SHA1 },
02796     { "sha224",         PGPHASHALGO_SHA224 },
02797     { "sha256",         PGPHASHALGO_SHA256 },
02798     { "sha384",         PGPHASHALGO_SHA384 },
02799     { "sha512",         PGPHASHALGO_SHA512 },
02800     { "tiger192",       PGPHASHALGO_TIGER192 },
02801 };
02802 /*@unchecked@*/
02803 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]);
02804 
02808 enum keyStat_e {
02809     STAT_KEYS_NONE      = 0,
02810     STAT_KEYS_DEV       = (1U <<  0),   
02811     STAT_KEYS_INO       = (1U <<  1),   
02812     STAT_KEYS_MODE      = (1U <<  2),   
02813     STAT_KEYS_NLINK     = (1U <<  3),   
02814     STAT_KEYS_UID       = (1U <<  4),   
02815     STAT_KEYS_GID       = (1U <<  5),   
02816     STAT_KEYS_RDEV      = (1U <<  6),   
02817     STAT_KEYS_SIZE      = (1U <<  7),   
02818     STAT_KEYS_BLKSIZE   = (1U <<  8),   
02819     STAT_KEYS_BLOCKS    = (1U <<  9),   
02820     STAT_KEYS_ATIME     = (1U << 10),   
02821     STAT_KEYS_CTIME     = (1U << 11),   
02822     STAT_KEYS_MTIME     = (1U << 12),   
02823 #ifdef  NOTYET
02824     STAT_KEYS_FLAGS     = (1U << 13),   
02825 #endif
02826     STAT_KEYS_SLINK     = (1U << 14),   
02827     STAT_KEYS_DIGEST    = (1U << 15),   
02828 #ifdef  NOTYET
02829     STAT_KEYS_FCONTEXT  = (1U << 16),   
02830 #endif
02831     STAT_KEYS_UNAME     = (1U << 17),   
02832     STAT_KEYS_GNAME     = (1U << 18),   
02833 };
02834 
02835 /*@unchecked@*/ /*@observer@*/
02836 static KEY keyStat[] = {
02837     { "adler32",        STAT_KEYS_DIGEST },
02838     { "atime",          STAT_KEYS_ATIME },
02839     { "ctime",          STAT_KEYS_CTIME },
02840     { "blksize",        STAT_KEYS_BLKSIZE },
02841     { "blocks",         STAT_KEYS_BLOCKS },
02842     { "crc32",          STAT_KEYS_DIGEST },
02843     { "crc64",          STAT_KEYS_DIGEST },
02844     { "dev",            STAT_KEYS_DEV },
02845 #ifdef  NOTYET
02846     { "digest",         STAT_KEYS_DIGEST },
02847     { "fcontext",       STAT_KEYS_FCONTEXT },
02848     { "flags",          STAT_KEYS_FLAGS },
02849 #endif
02850     { "gid",            STAT_KEYS_GID },
02851     { "gname",          STAT_KEYS_GNAME },
02852     { "haval160",       STAT_KEYS_DIGEST },
02853     { "ino",            STAT_KEYS_INO },
02854     { "jlu32",          STAT_KEYS_DIGEST },
02855     { "link",           STAT_KEYS_SLINK },
02856     { "md2",            STAT_KEYS_DIGEST },
02857     { "md4",            STAT_KEYS_DIGEST },
02858     { "md5",            STAT_KEYS_DIGEST },
02859     { "mode",           STAT_KEYS_MODE },
02860     { "mtime",          STAT_KEYS_MTIME },
02861     { "nlink",          STAT_KEYS_NLINK },
02862     { "rdev",           STAT_KEYS_RDEV },
02863     { "rmd128",         STAT_KEYS_DIGEST },
02864     { "rmd160",         STAT_KEYS_DIGEST },
02865     { "rmd256",         STAT_KEYS_DIGEST },
02866     { "rmd320",         STAT_KEYS_DIGEST },
02867     { "salsa10",        STAT_KEYS_DIGEST },
02868     { "salsa20",        STAT_KEYS_DIGEST },
02869     { "sha1",           STAT_KEYS_DIGEST },
02870     { "sha224",         STAT_KEYS_DIGEST },
02871     { "sha256",         STAT_KEYS_DIGEST },
02872     { "sha384",         STAT_KEYS_DIGEST },
02873     { "sha512",         STAT_KEYS_DIGEST },
02874     { "size",           STAT_KEYS_SIZE },
02875     { "tiger192",       STAT_KEYS_DIGEST },
02876     { "uid",            STAT_KEYS_UID },
02877     { "uname",          STAT_KEYS_UNAME },
02878 };
02879 /*@unchecked@*/
02880 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]);
02881 
02885 enum keyUuids_e {
02886     UUID_KEYS_NONE      = (0U <<  0),
02887     UUID_KEYS_V1        = (1U <<  0),
02888     UUID_KEYS_V3        = (3U <<  0),
02889     UUID_KEYS_V4        = (4U <<  0),
02890     UUID_KEYS_V5        = (5U <<  0),
02891 #ifdef  NOTYET
02892     UUID_KEYS_STRING    = (0U <<  4),
02893     UUID_KEYS_SIV       = (1U <<  4),
02894     UUID_KEYS_BINARY    = (2U <<  4),
02895     UUID_KEYS_TEXT      = (3U <<  4),
02896 #endif
02897 };
02898 
02899 /*@unchecked@*/ /*@observer@*/
02900 static KEY keyUuids[] = {
02901 #ifdef  NOTYET
02902     { "binary",         UUID_KEYS_BINARY },
02903     { "siv",            UUID_KEYS_SIV },
02904     { "string",         UUID_KEYS_STRING },
02905     { "text",           UUID_KEYS_TEXT },
02906 #endif
02907     { "v1",             UUID_KEYS_V1 },
02908     { "v3",             UUID_KEYS_V3 },
02909     { "v4",             UUID_KEYS_V4 },
02910     { "v5",             UUID_KEYS_V5 },
02911 };
02912 /*@unchecked@*/
02913 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]);
02914 
02917 static int
02918 keyCmp(const void * a, const void * b)
02919         /*@*/
02920 {
02921     return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
02922 }
02923 
02926 static uint32_t
02927 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name)
02928         /*@*/
02929 {
02930     uint32_t keyval = 0;
02931 
02932     if (name && * name) {
02933         KEY needle = { .name = name };
02934         KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp);
02935         if (k)
02936             keyval = k->value;
02937     }
02938     return keyval;
02939 }
02940 
02947 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av)
02948         /*@*/
02949 {
02950     int ix = (he->ix > 0 ? he->ix : 0);
02951     char * val = NULL;
02952     size_t ns;
02953 
02954 assert(ix == 0);
02955     switch(he->t) {
02956     default:
02957         val = xstrdup(_("(invalid type :digest)"));
02958         goto exit;
02959         /*@notreached@*/ break;
02960     case RPM_UINT64_TYPE:
02961         ns = sizeof(he->p.ui64p[0]);
02962         break;
02963     case RPM_STRING_TYPE:
02964         ns = strlen(he->p.str);
02965         break;
02966     case RPM_BIN_TYPE:
02967         ns = he->c;
02968         break;
02969     }
02970 
02971     {   uint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL));
02972         uint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1);
02973         DIGEST_CTX ctx = rpmDigestInit(algo, 0);
02974         int xx = rpmDigestUpdate(ctx, he->p.ptr, ns);
02975         xx = rpmDigestFinal(ctx, &val, NULL, 1);
02976     }
02977 
02978 exit:
02979 /*@-globstate@*/
02980     return val;
02981 /*@=globstate@*/
02982 }
02983 
02990 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av)
02991         /*@*/
02992 {
02993     /*@unchecked@*/
02994     static const char *avdefault[] = { "mode", NULL };
02995     const char * fn = NULL;
02996     struct stat sb, *st = &sb;
02997     int ix = (he->ix > 0 ? he->ix : 0);
02998     char * val = NULL;
02999     int xx;
03000     int i;
03001 
03002 assert(ix == 0);
03003     switch(he->t) {
03004     case RPM_BIN_TYPE:
03005         /* XXX limit to RPMTAG_PACKAGESTAT ... */
03006         if (he->tag == RPMTAG_PACKAGESTAT)
03007         if (he->c == sizeof(*st)) {
03008             st = (struct stat *)he->p.ptr;
03009             break;
03010         }
03011         /*@fallthrough @*/
03012     default:
03013         val = xstrdup(_("(invalid type :stat)"));
03014         goto exit;
03015         /*@notreached@*/ break;
03016     case RPM_STRING_TYPE:
03017         fn = he->p.str;
03018         if (Lstat(fn, st) == 0)
03019             break;
03020         val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL);
03021         goto exit;
03022         /*@notreached@*/ break;
03023     }
03024 
03025     if (!(av && av[0] && *av[0]))
03026         av = avdefault;
03027     for (i = 0; av[i] != NULL; i++) {
03028         char b[BUFSIZ];
03029         size_t nb = sizeof(b);
03030         char * nval;
03031         uint32_t keyval = keyValue(keyStat, nkeyStat, av[i]);
03032 
03033         nval = NULL;
03034         b[0] = '\0';
03035         switch (keyval) {
03036         default:
03037             break;
03038         case STAT_KEYS_NONE:
03039             break;
03040         case STAT_KEYS_DEV:
03041             xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev);
03042             break;
03043         case STAT_KEYS_INO:
03044             xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino);
03045             break;
03046         case STAT_KEYS_MODE:
03047             xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode);
03048             break;
03049         case STAT_KEYS_NLINK:
03050             xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink);
03051             break;
03052         case STAT_KEYS_UID:
03053             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid);
03054             break;
03055         case STAT_KEYS_GID:
03056             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid);
03057             break;
03058         case STAT_KEYS_RDEV:
03059             xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev);
03060             break;
03061         case STAT_KEYS_SIZE:
03062             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size);
03063             break;
03064         case STAT_KEYS_BLKSIZE:
03065             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize);
03066             break;
03067         case STAT_KEYS_BLOCKS:
03068             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks);
03069             break;
03070         case STAT_KEYS_ATIME:
03071             (void) stpcpy(b, ctime(&st->st_atime));
03072             break;
03073         case STAT_KEYS_CTIME:
03074             (void) stpcpy(b, ctime(&st->st_ctime));
03075             break;
03076         case STAT_KEYS_MTIME:
03077             (void) stpcpy(b, ctime(&st->st_mtime));
03078             break;
03079 #ifdef  NOTYET
03080         case STAT_KEYS_FLAGS:
03081             break;
03082 #endif
03083         case STAT_KEYS_SLINK:
03084             if (fn != NULL && S_ISLNK(st->st_mode)) {
03085                 ssize_t size = Readlink(fn, b, nb);
03086                 if (size == -1) {
03087                     nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL);
03088                     stpcpy(b, nval);
03089                     nval = _free(nval);
03090                 } else
03091                     b[size] = '\0';
03092             }
03093             break;
03094         case STAT_KEYS_DIGEST:
03095             if (fn != NULL && S_ISREG(st->st_mode)) {
03096                 uint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]);
03097                 uint32_t algo = (digval ? digval : PGPHASHALGO_SHA1);
03098                 FD_t fd = Fopen(fn, "r%{?_rpmgio}");
03099                 if (fd == NULL || Ferror(fd)) {
03100                     nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL);
03101                 } else {
03102                     static int asAscii = 1;
03103                     char buffer[16 * 1024];
03104                     fdInitDigest(fd, algo, 0);
03105                     while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
03106                         {};
03107                     if (Ferror(fd))
03108                         nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL);
03109                     else
03110                         fdFiniDigest(fd, algo, &nval, NULL, asAscii);
03111             }
03112                 if (nval) {
03113                     stpcpy(b, nval);
03114                     nval = _free(nval);
03115                 }
03116                 if (fd != NULL)
03117                     xx = Fclose(fd);
03118             }
03119             break;
03120         case STAT_KEYS_UNAME:
03121             (void) stpcpy(b, uidToUname(st->st_uid));
03122             break;
03123         case STAT_KEYS_GNAME:
03124             (void) stpcpy(b, gidToGname(st->st_gid));
03125             break;
03126         }
03127         if (b[0] == '\0')
03128             continue;
03129         b[nb-1] = '\0';
03130 
03131         if (val == NULL)
03132             val = xstrdup(b);
03133         else {
03134             nval = rpmExpand(val, " | ", b, NULL);
03135             val = _free(val);
03136             val = nval;
03137         }
03138     }
03139 
03140 exit:
03141 /*@-globstate@*/
03142     return val;
03143 /*@=globstate@*/
03144 }
03145 
03152 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av)
03153         /*@*/
03154 {
03155     /*@unchecked@*/
03156     static const char *avdefault[] = { "v5", NULL };
03157     int version = 0;
03158     int ix = (he->ix > 0 ? he->ix : 0);
03159     char * val = NULL;
03160     int i;
03161 
03162 assert(ix == 0);
03163     switch(he->t) {
03164     default:
03165         val = xstrdup(_("(invalid type :uuid)"));
03166         goto exit;
03167         /*@notreached@*/ break;
03168     case RPM_STRING_TYPE:
03169         break;
03170     }
03171 
03172     if (!(av && av[0] && *av[0]))
03173         av = avdefault;
03174 
03175     for (i = 0; av[i] != NULL; i++) {
03176         uint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]);
03177 
03178         switch (keyval) {
03179         default:
03180             break;
03181         case UUID_KEYS_V1:
03182         case UUID_KEYS_V3:
03183         case UUID_KEYS_V4:
03184         case UUID_KEYS_V5:
03185             version = keyval;
03186             break;
03187         }
03188     }
03189 
03190     /* XXX use private tag container to avoid memory issues for now. */
03191     {   HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
03192         int xx;
03193         nhe->tag = he->tag;
03194         nhe->t = he->t;
03195         nhe->p.str = xstrdup(he->p.str);
03196         nhe->c = he->c;
03197         val = xmalloc((128/4 + 4) + 1);
03198         xx = str2uuid(nhe, NULL, version, val);
03199         nhe->p.ptr = _free(nhe->p.ptr);
03200     }
03201 
03202 exit:
03203 /*@-globstate@*/
03204     return val;
03205 /*@=globstate@*/
03206 }
03207 
03214 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av)
03215         /*@*/
03216 {
03217     int ac = argvCount(av) + 1;
03218     int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack)));
03219     char * end;
03220     char * val = NULL;
03221     int ix = 0;
03222     int i;
03223 
03224     switch(he->t) {
03225     default:
03226         val = xstrdup(_("(invalid type :rpn)"));
03227         goto exit;
03228         /*@notreached@*/ break;
03229     case RPM_UINT64_TYPE:
03230         stack[ix] = he->p.ui64p[0];
03231         break;
03232     case RPM_STRING_TYPE:
03233         end = NULL;
03234         stack[ix] = strtoll(he->p.str, &end, 0);
03235         if (*end != '\0') {
03236             val = xstrdup(_("(invalid string :rpn)"));
03237             goto exit;
03238         }
03239         break;
03240     }
03241 
03242     if (av != NULL)
03243     for (i = 0; av[i] != NULL; i++) {
03244         const char * arg = av[i];
03245         size_t len = strlen(arg);
03246         int c = *arg;
03247 
03248         if (len == 0) {
03249             /* do nothing */
03250         } else if (len > 1) {
03251             if (!(xisdigit(c) || (c == '-' && xisdigit(arg[1])))) {
03252                 val = xstrdup(_("(expected number :rpn)"));
03253                 goto exit;
03254             }
03255             if (++ix == ac) {
03256                 val = xstrdup(_("(stack overflow :rpn)"));
03257                 goto exit;
03258             }
03259             end = NULL;
03260             stack[ix] = strtoll(arg, &end, 0);
03261             if (*end != '\0') {
03262                 val = xstrdup(_("(invalid number :rpn)"));
03263                 goto exit;
03264             }
03265         } else {
03266             if (ix-- < 1) {
03267                 val = xstrdup(_("(stack underflow :rpn)"));
03268                 goto exit;
03269             }
03270             switch (c) {
03271             case '&':   stack[ix] &= stack[ix+1];       break;
03272             case '|':   stack[ix] |= stack[ix+1];       break;
03273             case '^':   stack[ix] ^= stack[ix+1];       break;
03274             case '+':   stack[ix] += stack[ix+1];       break;
03275             case '-':   stack[ix] -= stack[ix+1];       break;
03276             case '*':   stack[ix] *= stack[ix+1];       break;
03277             case '%':   
03278             case '/':   
03279                 if (stack[ix+1] == 0) {
03280                     val = xstrdup(_("(divide by zero :rpn)"));
03281                     goto exit;
03282                 }
03283                 if (c == '%')
03284                     stack[ix] %= stack[ix+1];
03285                 else
03286                     stack[ix] /= stack[ix+1];
03287                 break;
03288             }
03289         }
03290     }
03291 
03292     {   HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
03293         nhe->tag = he->tag;
03294         nhe->t = RPM_UINT64_TYPE;
03295         nhe->p.ui64p = (uint64_t *)&stack[ix];
03296         nhe->c = 1;
03297         val = intFormat(nhe, NULL, NULL);
03298     }
03299 
03300 exit:
03301 /*@-globstate@*/
03302     return val;
03303 /*@=globstate@*/
03304 }
03305 
03306 /*@-type@*/ /* FIX: cast? */
03307 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
03308     { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID",
03309         { .tagFunction = buildtime_uuidTag } },
03310     { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
03311         { .tagFunction = changelognameTag } },
03312     { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
03313         { .tagFunction = changelogtextTag } },
03314     { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
03315         { .tagFunction = descriptionTag } },
03316     { HEADER_EXT_TAG, "RPMTAG_ENHANCES",
03317         { .tagFunction = missingokTag } },
03318     { HEADER_EXT_TAG, "RPMTAG_FILECLASS",
03319         { .tagFunction = fileclassTag } },
03320     { HEADER_EXT_TAG, "RPMTAG_FILECONTEXTS",
03321         { .tagFunction = filecontextsTag } },
03322     { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
03323         { .tagFunction = filepathsTag } },
03324     { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
03325         { .tagFunction = origpathsTag } },
03326     { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE",
03327         { .tagFunction = fileprovideTag } },
03328     { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE",
03329         { .tagFunction = filerequireTag } },
03330     { HEADER_EXT_TAG, "RPMTAG_FSCONTEXTS",
03331         { .tagFunction = fscontextsTag } },
03332     { HEADER_EXT_TAG, "RPMTAG_FSNAMES", 
03333         { .tagFunction = fsnamesTag } },
03334     { HEADER_EXT_TAG, "RPMTAG_FSSIZES", 
03335         { .tagFunction = fssizesTag } },
03336     { HEADER_EXT_TAG, "RPMTAG_GROUP",
03337         { .tagFunction = groupTag } },
03338     { HEADER_EXT_TAG, "RPMTAG_HDRUUID",
03339         { .tagFunction = hdruuidTag } },
03340     { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
03341         { .tagFunction = instprefixTag } },
03342     { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID",
03343         { .tagFunction = installtid_uuidTag } },
03344     { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID",
03345         { .tagFunction = installtime_uuidTag } },
03346     { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID",
03347         { .tagFunction = origintid_uuidTag } },
03348     { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID",
03349         { .tagFunction = origintime_uuidTag } },
03350     { HEADER_EXT_TAG, "RPMTAG_PKGUUID",
03351         { .tagFunction = pkguuidTag } },
03352     { HEADER_EXT_TAG, "RPMTAG_RECONTEXTS",
03353         { .tagFunction = recontextsTag } },
03354     { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID",
03355         { .tagFunction = removetid_uuidTag } },
03356     { HEADER_EXT_TAG, "RPMTAG_SUGGESTS",
03357         { .tagFunction = missingokTag } },
03358     { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID",
03359         { .tagFunction = sourcepkguuidTag } },
03360     { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
03361         { .tagFunction = summaryTag } },
03362     { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
03363         { .tagFunction = triggercondsTag } },
03364     { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
03365         { .tagFunction = triggertypeTag } },
03366     { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
03367         { .tagFunction = dbinstanceTag } },
03368     { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF",
03369         { .tagFunction = headerstartoffTag } },
03370     { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF",
03371         { .tagFunction = headerendoffTag } },
03372     { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL",
03373         { .tagFunction = pkgbaseurlTag } },
03374     { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST",
03375         { .tagFunction = pkgdigestTag } },
03376     { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN",
03377         { .tagFunction = pkgoriginTag } },
03378     { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE",
03379         { .tagFunction = pkgsizeTag } },
03380     { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME",
03381         { .tagFunction = pkgmtimeTag } },
03382     { HEADER_EXT_TAG, "RPMTAG_NVRA",
03383         { .tagFunction = nvraTag } },
03384     { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY",
03385         { .tagFunction = PxmlTag } },
03386     { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY",
03387         { .tagFunction = RxmlTag } },
03388     { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY",
03389         { .tagFunction = CxmlTag } },
03390     { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY",
03391         { .tagFunction = OxmlTag } },
03392     { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1",
03393         { .tagFunction = F1xmlTag } },
03394     { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2",
03395         { .tagFunction = F2xmlTag } },
03396     { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY",
03397         { .tagFunction = PsqlTag } },
03398     { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY",
03399         { .tagFunction = RsqlTag } },
03400     { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY",
03401         { .tagFunction = CsqlTag } },
03402     { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY",
03403         { .tagFunction = OsqlTag } },
03404     { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1",
03405         { .tagFunction = F1sqlTag } },
03406     { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2",
03407         { .tagFunction = F2sqlTag } },
03408     { HEADER_EXT_FORMAT, "armor",
03409         { .fmtFunction = armorFormat } },
03410     { HEADER_EXT_FORMAT, "base64",
03411         { .fmtFunction = base64Format } },
03412     { HEADER_EXT_FORMAT, "bncdata",
03413         { .fmtFunction = bncdataFormat } },
03414     { HEADER_EXT_FORMAT, "cdata",
03415         { .fmtFunction = cdataFormat } },
03416     { HEADER_EXT_FORMAT, "depflags",
03417         { .fmtFunction = depflagsFormat } },
03418     { HEADER_EXT_FORMAT, "digest",
03419         { .fmtFunction = digestFormat } },
03420     { HEADER_EXT_FORMAT, "fflags",
03421         { .fmtFunction = fflagsFormat } },
03422     { HEADER_EXT_FORMAT, "iconv",
03423         { .fmtFunction = iconvFormat } },
03424     { HEADER_EXT_FORMAT, "perms",
03425         { .fmtFunction = permsFormat } },
03426     { HEADER_EXT_FORMAT, "permissions", 
03427         { .fmtFunction = permsFormat } },
03428     { HEADER_EXT_FORMAT, "pgpsig",
03429         { .fmtFunction = pgpsigFormat } },
03430     { HEADER_EXT_FORMAT, "rpn",
03431         { .fmtFunction = rpnFormat } },
03432     { HEADER_EXT_FORMAT, "sqlescape",
03433         { .fmtFunction = sqlescapeFormat } },
03434     { HEADER_EXT_FORMAT, "stat",
03435         { .fmtFunction = statFormat } },
03436     { HEADER_EXT_FORMAT, "triggertype",
03437         { .fmtFunction = triggertypeFormat } },
03438     { HEADER_EXT_FORMAT, "utf8",
03439         { .fmtFunction = iconvFormat } },
03440     { HEADER_EXT_FORMAT, "uuid",
03441         { .fmtFunction = uuidFormat } },
03442     { HEADER_EXT_FORMAT, "xml", 
03443         { .fmtFunction = xmlFormat } },
03444     { HEADER_EXT_FORMAT, "yaml",
03445         { .fmtFunction = yamlFormat } },
03446     { HEADER_EXT_MORE, NULL,
03447         { .more = (void *) headerDefaultFormats } }
03448 } ;
03449 /*@=type@*/

Generated on Mon Aug 23 10:39:54 2010 for rpm by  doxygen 1.5.1