rpm  5.4.4
rpmdb/tagname.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio_internal.h>     /* XXX DIGEST_CTX, xtolower, xstrcasecmp */
00008 #include <rpmmacro.h>
00009 #include <argv.h>
00010 #define _RPMTAG_INTERNAL
00011 #include <rpmtag.h>
00012 #include "debug.h"
00013 
00014 /*@access headerTagTableEntry @*/
00015 /*@access headerTagIndices @*/
00016 
00022 static int tagLoadATags(/*@null@*/ ARGV_t * argvp,
00023                 int (*cmp) (const void * avp, const void * bvp))
00024         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00025         /*@modifies *argvp, rpmGlobalMacroContext, internalState @*/
00026 {
00027     ARGV_t aTags = NULL;
00028     char * s = rpmExpand("%{?_arbitrary_tags}", NULL);
00029 
00030     if (s && *s)
00031         (void) argvSplit(&aTags, s, ":");
00032     else
00033         aTags = xcalloc(1, sizeof(*aTags));
00034     if (aTags && aTags[0] && aTags[1])
00035         (void) argvSort(aTags, (int (*) (const char **, const char **))cmp);
00036     s = _free(s);
00037 
00038     if (argvp)
00039         *argvp = aTags;
00040     else
00041         aTags = argvFree(aTags);
00042 /*@-nullstate@*/        /* *argvp may be NULL */
00043     return 0;
00044 /*@=nullstate@*/
00045 }
00046 
00053 static int tagCmpName(const void * avp, const void * bvp)
00054         /*@*/
00055 {
00056     headerTagTableEntry a = *(headerTagTableEntry *) avp;
00057     headerTagTableEntry b = *(headerTagTableEntry *) bvp;
00058     return strcmp(a->name, b->name);
00059 }
00060 
00067 static int tagCmpValue(const void * avp, const void * bvp)
00068         /*@*/
00069 {
00070     headerTagTableEntry a = *(headerTagTableEntry *) avp;
00071     headerTagTableEntry b = *(headerTagTableEntry *) bvp;
00072     int ret = ((int)a->val - (int)b->val);
00073     /* Make sure that sort is stable, longest name first. */
00074     if (ret == 0)
00075         ret = ((int)strlen(b->name) - (int)strlen(a->name));
00076     return ret;
00077 }
00078 
00086 static int tagLoadIndex(headerTagTableEntry ** ipp, size_t * np,
00087                 int (*cmp) (const void * avp, const void * bvp))
00088         /*@modifies *ipp, *np @*/
00089 {
00090     headerTagTableEntry tte, *ip;
00091     size_t n = 0;
00092 
00093     ip = xcalloc(rpmTagTableSize, sizeof(*ip));
00094     n = 0;
00095 /*@-dependenttrans@*/ /*@-observertrans@*/ /*@-castexpose@*/ /*@-mods@*/ /*@-modobserver@*/
00096     for (tte = rpmTagTable; tte->name != NULL; tte++) {
00097         ip[n] = tte;
00098         n++;
00099     }
00100 assert(n == (size_t)rpmTagTableSize);
00101 /*@=dependenttrans@*/ /*@=observertrans@*/ /*@=castexpose@*/ /*@=mods@*/ /*@=modobserver@*/
00102 
00103     if (n > 1)
00104         qsort(ip, n, sizeof(*ip), cmp);
00105     *ipp = ip;
00106     *np = n;
00107     return 0;
00108 }
00109 
00110 static char * _tagCanonicalize(const char * s)
00111         /*@*/
00112 {
00113     const char * se;
00114     size_t nb = 0;
00115     char * te;
00116     char * t;
00117     int c;
00118 
00119     if (!strncasecmp(s, "RPMTAG_", sizeof("RPMTAG_")-1))
00120         s += sizeof("RPMTAG_") - 1;
00121     se = s;
00122     while ((c = (int)*se++) && xisalnum(c))
00123         nb++;
00124 
00125     te = t = xmalloc(nb+1);
00126     if (*s != '\0' && nb > 0) {
00127         *te++ = (char) xtoupper((int)*s++);
00128         nb--;
00129     }
00130     while (nb--)
00131         *te++ = (char) xtolower((int)*s++);
00132     *te = '\0';
00133 
00134     return t;
00135 }
00136 
00137 static rpmTag _tagGenerate(const char *s)
00138         /*@*/
00139 {
00140     DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00141     const char * digest = NULL;
00142     size_t digestlen = 0;
00143     size_t nb = strlen(s);
00144     rpmTag tag = 0;
00145     int xx;
00146 
00147     xx = rpmDigestUpdate(ctx, s, nb);
00148     xx = rpmDigestFinal(ctx, &digest, &digestlen, 0);
00149     if (digest && digestlen > 4) {
00150         memcpy(&tag, digest + (digestlen - 4), 4);
00151         tag &= 0x3fffffff;
00152         tag |= 0x40000000;
00153     }
00154     digest = _free(digest);
00155     return tag;
00156 }
00157 
00158 /* forward refs */
00159 static const char * _tagName(rpmTag tag)
00160         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00161         /*@modifies rpmGlobalMacroContext, internalState @*/;
00162 static unsigned int _tagType(rpmTag tag)
00163         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00164         /*@modifies rpmGlobalMacroContext, internalState @*/;
00165 static rpmTag _tagValue(const char * tagstr)
00166         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00167         /*@modifies rpmGlobalMacroContext, internalState @*/;
00168 
00169 /*@unchecked@*/
00170 static struct headerTagIndices_s _rpmTags = {
00171     tagLoadIndex,
00172     NULL, 0, tagCmpName, _tagValue,
00173     NULL, 0, tagCmpValue, _tagName, _tagType,
00174     256, NULL, NULL, _tagCanonicalize, _tagGenerate
00175 };
00176 
00177 /*@-compmempass@*/
00178 /*@unchecked@*/
00179 headerTagIndices rpmTags = &_rpmTags;
00180 /*@=compmempass@*/
00181 
00182 /*@-mods@*/
00183 static const char * _tagName(rpmTag tag)
00184 {
00185     char * nameBuf;
00186     size_t nameBufLen = 0;
00187     headerTagTableEntry t;
00188     size_t i, l, u;
00189     int comparison;
00190     int xx;
00191     char *s;
00192 
00193     if (_rpmTags.aTags == NULL)
00194         xx = tagLoadATags(&_rpmTags.aTags, NULL);
00195     if (_rpmTags.byValue == NULL)
00196         xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize,
00197                 tagCmpValue);
00198     if (_rpmTags.nameBufLen == 0)
00199         _rpmTags.nameBufLen = 256;
00200     if (_rpmTags.nameBuf == NULL)
00201         _rpmTags.nameBuf = xcalloc(1, _rpmTags.nameBufLen);
00202     nameBuf = _rpmTags.nameBuf;
00203     nameBuf[0] = nameBuf[1] = '\0';
00204     nameBufLen = _rpmTags.nameBufLen;
00205 
00206     switch (tag) {
00207     case RPMDBI_PACKAGES:
00208         strncpy(nameBuf, "Packages", nameBufLen);
00209         break;
00210     case RPMDBI_DEPCACHE:
00211         strncpy(nameBuf, "Depcache", nameBufLen);
00212         break;
00213     case RPMDBI_ADDED:
00214         strncpy(nameBuf, "Added", nameBufLen);
00215         break;
00216     case RPMDBI_REMOVED:
00217         strncpy(nameBuf, "Removed", nameBufLen);
00218         break;
00219     case RPMDBI_AVAILABLE:
00220         strncpy(nameBuf, "Available", nameBufLen);
00221         break;
00222     case RPMDBI_HDLIST:
00223         strncpy(nameBuf, "Hdlist", nameBufLen);
00224         break;
00225     case RPMDBI_ARGLIST:
00226         strncpy(nameBuf, "Arglist", nameBufLen);
00227         break;
00228     case RPMDBI_FTSWALK:
00229         strncpy(nameBuf, "Ftswalk", nameBufLen);
00230         break;
00231     case RPMDBI_SEQNO:
00232         strncpy(nameBuf, "Seqno", nameBufLen);
00233         break;
00234     case RPMDBI_BTREE:
00235         strncpy(nameBuf, "Btree", nameBufLen);
00236         break;
00237     case RPMDBI_HASH:
00238         strncpy(nameBuf, "Hash", nameBufLen);
00239         break;
00240     case RPMDBI_QUEUE:
00241         strncpy(nameBuf, "Queue", nameBufLen);
00242         break;
00243     case RPMDBI_RECNO:
00244         strncpy(nameBuf, "Recno", nameBufLen);
00245         break;
00246     case RPMDBI_HEAP:
00247         strncpy(nameBuf, "Heap", nameBufLen);
00248         break;
00249 
00250     /* XXX make sure rpmdb indices are identically named. */
00251     case RPMTAG_CONFLICTS:
00252         strncpy(nameBuf, "Conflictname", nameBufLen);
00253         break;
00254     case RPMTAG_HDRID:
00255         strncpy(nameBuf, "Sha1header", nameBufLen);
00256         break;
00257 
00258     /* XXX make sure that h.['filenames'] in python "works". */
00259     case 0x54aafb71:
00260         strncpy(nameBuf, "Filenames", nameBufLen);
00261         break;
00262 
00263     default:
00264         if (_rpmTags.byValue == NULL)
00265             break;
00266         l = 0;
00267         u = _rpmTags.byValueSize;
00268         while (l < u) {
00269             i = (l + u) / 2;
00270             t = _rpmTags.byValue[i];
00271         
00272             comparison = ((int)tag - (int)t->val);
00273 
00274             if (comparison < 0)
00275                 u = i;
00276             else if (comparison > 0)
00277                 l = i + 1;
00278             else {
00279                 /* Make sure that the bsearch retrieve is stable. */
00280                 while (i > 0 && tag == _rpmTags.byValue[i-1]->val) {
00281                     i--;
00282                     t = _rpmTags.byValue[i];
00283                 }
00284                 s = (*_rpmTags.tagCanonicalize) (t->name);
00285                 strncpy(nameBuf, s, nameBufLen);
00286                 s = _free(s);
00287                 /*@loopbreak@*/ break;
00288             }
00289         }
00290         break;
00291     }
00292     if (nameBuf[0] == '\0')
00293         xx = snprintf(nameBuf, nameBufLen, "Tag_0x%08x", (unsigned) tag);
00294     nameBuf[nameBufLen-1] = '\0';
00295 /*@-globstate@*/        /* _rpmTags.nameBuf reachable. */
00296     return nameBuf;
00297 /*@=globstate@*/
00298 }
00299 /*@=mods@*/
00300 
00301 static unsigned int _tagType(rpmTag tag)
00302 {
00303     headerTagTableEntry t;
00304     size_t i, l, u;
00305     int comparison;
00306     int xx;
00307 
00308     if (_rpmTags.aTags == NULL)
00309         xx = tagLoadATags(&_rpmTags.aTags, NULL);
00310     if (_rpmTags.byValue == NULL)
00311         xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
00312 
00313     switch (tag) {
00314     case RPMDBI_PACKAGES:
00315     case RPMDBI_DEPCACHE:
00316     case RPMDBI_ADDED:
00317     case RPMDBI_REMOVED:
00318     case RPMDBI_AVAILABLE:
00319     case RPMDBI_HDLIST:
00320     case RPMDBI_ARGLIST:
00321     case RPMDBI_FTSWALK:
00322     case RPMDBI_SEQNO:
00323     case RPMDBI_BTREE:
00324     case RPMDBI_HASH:
00325     case RPMDBI_QUEUE:
00326     case RPMDBI_RECNO:
00327     case RPMDBI_HEAP:
00328         break;
00329     default:
00330         if (_rpmTags.byValue == NULL)
00331             break;
00332         l = 0;
00333         u = _rpmTags.byValueSize;
00334         while (l < u) {
00335             i = (l + u) / 2;
00336             t = _rpmTags.byValue[i];
00337         
00338             comparison = ((int)tag - (int)t->val);
00339 
00340             if (comparison < 0)
00341                 u = i;
00342             else if (comparison > 0)
00343                 l = i + 1;
00344             else {
00345                 /* Make sure that the bsearch retrieve is stable. */
00346                 while (i > 0 && t->val == _rpmTags.byValue[i-1]->val) {
00347                     i--;
00348                     t = _rpmTags.byValue[i];
00349                 }
00350                 return t->type;
00351             }
00352         }
00353         break;
00354     }
00355     return 0;
00356 }
00357 
00358 static rpmTag _tagValue(const char * tagstr)
00359 {
00360     headerTagTableEntry t;
00361     int comparison;
00362     size_t i, l, u;
00363     const char * s;
00364     rpmTag tag;
00365     int xx;
00366 
00367     /* XXX headerSprintf looks up by "RPMTAG_FOO", not "FOO". */
00368     if (!strncasecmp(tagstr, "RPMTAG_", sizeof("RPMTAG_")-1))
00369         tagstr += sizeof("RPMTAG_") - 1;
00370 
00371     if (!xstrcasecmp(tagstr, "Packages"))
00372         return RPMDBI_PACKAGES;
00373     if (!xstrcasecmp(tagstr, "Depcache"))
00374         return RPMDBI_DEPCACHE;
00375     if (!xstrcasecmp(tagstr, "Added"))
00376         return RPMDBI_ADDED;
00377     if (!xstrcasecmp(tagstr, "Removed"))
00378         return RPMDBI_REMOVED;
00379     if (!xstrcasecmp(tagstr, "Available"))
00380         return RPMDBI_AVAILABLE;
00381     if (!xstrcasecmp(tagstr, "Hdlist"))
00382         return RPMDBI_HDLIST;
00383     if (!xstrcasecmp(tagstr, "Arglist"))
00384         return RPMDBI_ARGLIST;
00385     if (!xstrcasecmp(tagstr, "Ftswalk"))
00386         return RPMDBI_FTSWALK;
00387     if (!xstrcasecmp(tagstr, "Seqno"))
00388         return RPMDBI_SEQNO;
00389     if (!xstrcasecmp(tagstr, "Btree"))
00390         return RPMDBI_BTREE;
00391     if (!xstrcasecmp(tagstr, "Hash"))
00392         return RPMDBI_HASH;
00393     if (!xstrcasecmp(tagstr, "Queue"))
00394         return RPMDBI_QUEUE;
00395     if (!xstrcasecmp(tagstr, "Recno"))
00396         return RPMDBI_RECNO;
00397     if (!xstrcasecmp(tagstr, "Heap"))
00398         return RPMDBI_HEAP;
00399 
00400     if (_rpmTags.aTags == NULL)
00401         xx = tagLoadATags(&_rpmTags.aTags, NULL);
00402     if (_rpmTags.byName == NULL)
00403         xx = tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
00404     if (_rpmTags.byName == NULL)
00405         goto exit;
00406 
00407     l = 0;
00408     u = _rpmTags.byNameSize;
00409     while (l < u) {
00410         i = (l + u) / 2;
00411         t = _rpmTags.byName[i];
00412         
00413         comparison = xstrcasecmp(tagstr, t->name + (sizeof("RPMTAG_")-1));
00414 
00415         if (comparison < 0)
00416             u = i;
00417         else if (comparison > 0)
00418             l = i + 1;
00419         else
00420             return t->val;
00421     }
00422 
00423 exit:
00424     /* Generate an arbitrary tag string. */
00425     s = _tagCanonicalize(tagstr);
00426     tag = _tagGenerate(s);
00427     s = _free(s);
00428     return tag;
00429 }
00430 
00431 const char * tagName(rpmTag tag)
00432 {
00433     return ((*rpmTags->tagName)(tag));
00434 }
00435 
00436 unsigned int tagType(rpmTag tag)
00437 {
00438     return ((*rpmTags->tagType)(tag));
00439 }
00440 
00441 rpmTag tagValue(const char * tagstr)
00442 {
00443     return ((*rpmTags->tagValue)(tagstr));
00444 }
00445 
00446 char * tagCanonicalize(const char * s)
00447 {
00448     return ((*rpmTags->tagCanonicalize)(s));
00449 }
00450 
00451 rpmTag tagGenerate(const char * s)
00452 {
00453     return ((*rpmTags->tagGenerate)(s));
00454 }
00455 
00456 void tagClean(headerTagIndices _rpmTags)
00457 {
00458     if (_rpmTags == NULL)
00459         _rpmTags = rpmTags;
00460    if (_rpmTags) {
00461         _rpmTags->nameBuf = _free(_rpmTags->nameBuf);
00462         _rpmTags->byName = _free(_rpmTags->byName);
00463         _rpmTags->byValue = _free(_rpmTags->byValue);
00464         _rpmTags->aTags = argvFree(_rpmTags->aTags);
00465     }
00466 }
00467 
00468 tagStore_t tagStoreFree(tagStore_t dbiTags, size_t dbiNTags)
00469 {
00470     if (dbiTags != NULL) {
00471         size_t i;
00472         for (i = 0; i < dbiNTags; i++) {
00473             dbiTags[i].str = _free(dbiTags[i].str);
00474             dbiTags[i].iob = rpmiobFree(dbiTags[i].iob);
00475         }
00476         dbiTags = _free(dbiTags);
00477     }
00478     return NULL;
00479 }
00480 
00481 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
00482 
00486 void tagTypeValidate(HE_t he)
00487 {
00488 /* XXX hack around known borkage for now. */
00489 if (!he->signature)
00490 if (!(he->tag == 261 || he->tag == 269))
00491 if ((tagType(he->tag) & 0xffff) != he->t)
00492 fprintf(stderr, "==> warning: tag %u type(0x%x) != implicit type(0x%x)\n", (unsigned) he->tag, he->t, tagType(he->tag));
00493 }
00494 #endif