"Fossies" - the Fresh Open Source Software Archive

Member "rpm-4.15.0/lib/headerutil.c" (26 Jun 2019, 10128 Bytes) of package /linux/misc/rpm-4.15.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "headerutil.c" see the Fossies "Dox" file reference documentation.

    1 /** \ingroup rpmdb
    2  * \file lib/headerutil.c
    3  */
    4 
    5 #include "system.h"
    6 
    7 #include <rpm/rpmtypes.h>
    8 #include <rpm/header.h>
    9 #include <rpm/rpmstring.h>
   10 #include <rpm/rpmds.h>
   11 
   12 #include "debug.h"
   13 
   14 int headerIsSource(Header h)
   15 {
   16     return (!headerIsEntry(h, RPMTAG_SOURCERPM));
   17 }
   18 
   19 Header headerCopy(Header h)
   20 {
   21     Header nh = headerNew();
   22     HeaderIterator hi;
   23     struct rpmtd_s td;
   24    
   25     hi = headerInitIterator(h);
   26     while (headerNext(hi, &td)) {
   27     if (rpmtdCount(&td) > 0) {
   28         (void) headerPut(nh, &td, HEADERPUT_DEFAULT);
   29     }
   30     rpmtdFreeData(&td);
   31     }
   32     headerFreeIterator(hi);
   33 
   34     return nh;
   35 }
   36 
   37 void headerCopyTags(Header headerFrom, Header headerTo, 
   38             const rpmTagVal * tagstocopy)
   39 {
   40     const rpmTagVal * p;
   41     struct rpmtd_s td;
   42 
   43     if (headerFrom == headerTo)
   44     return;
   45 
   46     for (p = tagstocopy; *p != 0; p++) {
   47     if (headerIsEntry(headerTo, *p))
   48         continue;
   49     if (!headerGet(headerFrom, *p, &td, (HEADERGET_MINMEM|HEADERGET_RAW)))
   50         continue;
   51     (void) headerPut(headerTo, &td, HEADERPUT_DEFAULT);
   52     rpmtdFreeData(&td);
   53     }
   54 }
   55 
   56 char * headerGetAsString(Header h, rpmTagVal tag)
   57 {
   58     char *res = NULL;
   59     struct rpmtd_s td;
   60 
   61     if (headerGet(h, tag, &td, HEADERGET_EXT)) {
   62     if (rpmtdCount(&td) == 1) {
   63         res = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL);
   64     }
   65     rpmtdFreeData(&td);
   66     }
   67     return res;
   68 }
   69 
   70 const char * headerGetString(Header h, rpmTagVal tag)
   71 {
   72     const char *res = NULL;
   73     struct rpmtd_s td;
   74 
   75     if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
   76     if (rpmtdCount(&td) == 1) {
   77         res = rpmtdGetString(&td);
   78     }
   79     rpmtdFreeData(&td);
   80     }
   81     return res;
   82 }
   83 
   84 uint64_t headerGetNumber(Header h, rpmTagVal tag)
   85 {
   86     uint64_t res = 0;
   87     struct rpmtd_s td;
   88 
   89     if (headerGet(h, tag, &td, HEADERGET_EXT)) {
   90     if (rpmtdCount(&td) == 1) {
   91         res = rpmtdGetNumber(&td);
   92     }
   93     rpmtdFreeData(&td);
   94     }
   95     return res;
   96 }
   97 
   98 /*
   99  * Sanity check data types against tag table before putting. Assume
  100  * append on all array-types.
  101  */
  102 static int headerPutType(Header h, rpmTagVal tag, rpmTagType reqtype,
  103             rpm_constdata_t data, rpm_count_t size)
  104 {
  105     struct rpmtd_s td;
  106     rpmTagType type = rpmTagGetTagType(tag);
  107     rpmTagReturnType retype = rpmTagGetReturnType(tag);
  108     headerPutFlags flags = HEADERPUT_APPEND; 
  109     int valid = 1;
  110 
  111     /* Basic sanity checks: type must match and there must be data to put */
  112     if (type != reqtype 
  113     || size < 1 || data == NULL || h == NULL) {
  114     valid = 0;
  115     }
  116 
  117     /*
  118      * Non-array types can't be appended to. Binary types use size
  119      * for data length, for other non-array types size must be 1.
  120      */
  121     if (retype != RPM_ARRAY_RETURN_TYPE) {
  122     flags = HEADERPUT_DEFAULT;
  123     if (type != RPM_BIN_TYPE && size != 1) {
  124         valid = 0;
  125     }
  126     }
  127 
  128     if (valid) {
  129     rpmtdReset(&td);
  130     td.tag = tag;
  131     td.type = type;
  132     td.data = (void *) data;
  133     td.count = size;
  134 
  135     valid = headerPut(h, &td, flags);
  136     }
  137 
  138     return valid;
  139 }
  140     
  141 int headerPutString(Header h, rpmTagVal tag, const char *val)
  142 {
  143     rpmTagType type = rpmTagGetTagType(tag);
  144     const void *sptr = NULL;
  145 
  146     /* string arrays expect char **, arrange that */
  147     if (type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE) {
  148     sptr = &val;
  149     } else if (type == RPM_STRING_TYPE) {
  150     sptr = val;
  151     } else {
  152     return 0;
  153     }
  154 
  155     return headerPutType(h, tag, type, sptr, 1);
  156 }
  157 
  158 int headerPutStringArray(Header h, rpmTagVal tag, const char **array, rpm_count_t size)
  159 {
  160     return headerPutType(h, tag, RPM_STRING_ARRAY_TYPE, array, size);
  161 }
  162 
  163 int headerPutChar(Header h, rpmTagVal tag, const char *val, rpm_count_t size)
  164 {
  165     return headerPutType(h, tag, RPM_CHAR_TYPE, val, size);
  166 }
  167 
  168 int headerPutUint8(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size)
  169 {
  170     return headerPutType(h, tag, RPM_INT8_TYPE, val, size);
  171 }
  172 
  173 int headerPutUint16(Header h, rpmTagVal tag, const uint16_t *val, rpm_count_t size)
  174 {
  175     return headerPutType(h, tag, RPM_INT16_TYPE, val, size);
  176 }
  177 
  178 int headerPutUint32(Header h, rpmTagVal tag, const uint32_t *val, rpm_count_t size)
  179 {
  180     return headerPutType(h, tag, RPM_INT32_TYPE, val, size);
  181 }
  182 
  183 int headerPutUint64(Header h, rpmTagVal tag, const uint64_t *val, rpm_count_t size)
  184 {
  185     return headerPutType(h, tag, RPM_INT64_TYPE, val, size);
  186 }
  187 
  188 int headerPutBin(Header h, rpmTagVal tag, const uint8_t *val, rpm_count_t size)
  189 {
  190     return headerPutType(h, tag, RPM_BIN_TYPE, val, size);
  191 }
  192 
  193 static int dncmp(const void * a, const void * b)
  194 {
  195     const char *const * first = a;
  196     const char *const * second = b;
  197     return strcmp(*first, *second);
  198 }
  199 
  200 static void compressFilelist(Header h)
  201 {
  202     struct rpmtd_s fileNames;
  203     char ** dirNames;
  204     const char ** baseNames;
  205     uint32_t * dirIndexes;
  206     rpm_count_t count, realCount = 0;
  207     int i;
  208     int dirIndex = -1;
  209 
  210     /*
  211      * This assumes the file list is already sorted, and begins with a
  212      * single '/'. That assumption isn't critical, but it makes things go
  213      * a bit faster.
  214      */
  215 
  216     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
  217     headerDel(h, RPMTAG_OLDFILENAMES);
  218     return;     /* Already converted. */
  219     }
  220 
  221     if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM)) 
  222     return;
  223     count = rpmtdCount(&fileNames);
  224     if (count < 1) 
  225     return;
  226 
  227     dirNames = xmalloc(sizeof(*dirNames) * count);  /* worst case */
  228     baseNames = xmalloc(sizeof(*dirNames) * count);
  229     dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
  230 
  231     /* HACK. Source RPM, so just do things differently */
  232     {   const char *fn = rpmtdGetString(&fileNames);
  233     if (fn && *fn != '/') {
  234         dirIndex = 0;
  235         dirNames[dirIndex] = xstrdup("");
  236         while ((i = rpmtdNext(&fileNames)) >= 0) {
  237         dirIndexes[i] = dirIndex;
  238         baseNames[i] = rpmtdGetString(&fileNames);
  239         realCount++;
  240         }
  241         goto exit;
  242     }
  243     }
  244 
  245     /* 
  246      * XXX EVIL HACK, FIXME:
  247      * This modifies (and then restores) a const string from rpmtd
  248      * through basename retrieved from strrchr() which silently 
  249      * casts away const on return.
  250      */
  251     while ((i = rpmtdNext(&fileNames)) >= 0) {
  252     char ** needle;
  253     char savechar;
  254     char * baseName;
  255     size_t len;
  256     char *filename = (char *) rpmtdGetString(&fileNames); /* HACK HACK */
  257 
  258     if (filename == NULL)   /* XXX can't happen */
  259         continue;
  260     baseName = strrchr(filename, '/');
  261     if (baseName == NULL) {
  262         baseName = filename;
  263     } else {
  264         baseName += 1;
  265     }
  266     len = baseName - filename;
  267     needle = dirNames;
  268     savechar = *baseName;
  269     *baseName = '\0';
  270     if (dirIndex < 0 ||
  271         (needle = bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
  272         char *s = xmalloc(len + 1);
  273         rstrlcpy(s, filename, len + 1);
  274         dirIndexes[realCount] = ++dirIndex;
  275         dirNames[dirIndex] = s;
  276     } else
  277         dirIndexes[realCount] = needle - dirNames;
  278 
  279     *baseName = savechar;
  280     baseNames[realCount] = baseName;
  281     realCount++;
  282     }
  283 
  284 exit:
  285     if (count > 0) {
  286     headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, realCount);
  287     headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, realCount);
  288     headerPutStringArray(h, RPMTAG_DIRNAMES, 
  289                  (const char **) dirNames, dirIndex + 1);
  290     }
  291 
  292     rpmtdFreeData(&fileNames);
  293     for (i = 0; i <= dirIndex; i++) {
  294     free(dirNames[i]);
  295     }
  296     free(dirNames);
  297     free(baseNames);
  298     free(dirIndexes);
  299 
  300     headerDel(h, RPMTAG_OLDFILENAMES);
  301 }
  302 
  303 static void expandFilelist(Header h)
  304 {
  305     struct rpmtd_s filenames;
  306 
  307     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
  308     (void) headerGet(h, RPMTAG_FILENAMES, &filenames, HEADERGET_EXT);
  309     if (rpmtdCount(&filenames) < 1)
  310         return;
  311     rpmtdSetTag(&filenames, RPMTAG_OLDFILENAMES);
  312     headerPut(h, &filenames, HEADERPUT_DEFAULT);
  313     rpmtdFreeData(&filenames);
  314     }
  315 
  316     (void) headerDel(h, RPMTAG_DIRNAMES);
  317     (void) headerDel(h, RPMTAG_BASENAMES);
  318     (void) headerDel(h, RPMTAG_DIRINDEXES);
  319 }
  320 
  321 /*
  322  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
  323  * Retrofit an explicit "Provides: name = epoch:version-release.
  324  */
  325 static void providePackageNVR(Header h)
  326 {
  327     const char *name = headerGetString(h, RPMTAG_NAME);
  328     char *pEVR = headerGetAsString(h, RPMTAG_EVR);
  329     rpmsenseFlags pFlags = RPMSENSE_EQUAL;
  330     int bingo = 1;
  331     struct rpmtd_s pnames;
  332     rpmds hds, nvrds;
  333 
  334     /* Generate provides for this package name-version-release. */
  335     if (!(name && pEVR))
  336     return;
  337 
  338     /*
  339      * Rpm prior to 3.0.3 does not have versioned provides.
  340      * If no provides at all are available, we can just add.
  341      */
  342     if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
  343     goto exit;
  344     }
  345 
  346     /*
  347      * Otherwise, fill in entries on legacy packages.
  348      */
  349     if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
  350     while (rpmtdNext(&pnames) >= 0) {
  351         rpmsenseFlags fdummy = RPMSENSE_ANY;
  352 
  353         headerPutString(h, RPMTAG_PROVIDEVERSION, "");
  354         headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
  355     }
  356     goto exit;
  357     }
  358 
  359     /* see if we already have this provide */
  360     hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
  361     nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
  362     if (rpmdsFind(hds, nvrds) >= 0) {
  363     bingo = 0;
  364     }
  365     rpmdsFree(hds);
  366     rpmdsFree(nvrds);
  367     
  368 
  369 exit:
  370     if (bingo) {
  371     headerPutString(h, RPMTAG_PROVIDENAME, name);
  372     headerPutString(h, RPMTAG_PROVIDEVERSION, pEVR);
  373     headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pFlags, 1);
  374     }
  375     rpmtdFreeData(&pnames);
  376     free(pEVR);
  377 }
  378 
  379 static void legacyRetrofit(Header h)
  380 {
  381     /*
  382      * The file list was moved to a more compressed format which not
  383      * only saves memory (nice), but gives fingerprinting a nice, fat
  384      * speed boost (very nice). Go ahead and convert old headers to
  385      * the new style (this is a noop for new headers).
  386      */
  387      compressFilelist(h);
  388 
  389     /* Retrofit "Provide: name = EVR" for binary packages. */
  390     if (!headerIsSource(h)) {
  391     providePackageNVR(h);
  392     }
  393 }
  394 
  395 int headerConvert(Header h, int op)
  396 {
  397     int rc = 1;
  398 
  399     if (h == NULL)
  400     return 0;
  401 
  402     switch (op) {
  403     case HEADERCONV_EXPANDFILELIST:
  404     expandFilelist(h);
  405     break;
  406     case HEADERCONV_COMPRESSFILELIST:
  407     compressFilelist(h);
  408     break;
  409     case HEADERCONV_RETROFIT_V3:
  410     legacyRetrofit(h);
  411     break;
  412     default:
  413     rc = 0;
  414     break;
  415     }
  416     return rc;
  417 };
  418