Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

lib/misc.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 static int _debug = 0;
00008 
00009 #include <rpmlib.h>
00010 #include <rpmurl.h>
00011 #include <rpmmacro.h>   /* XXX for rpmGetPath */
00012 
00013 #include "misc.h"
00014 #include "debug.h"
00015 
00016 /*@access Header@*/             /* XXX compared with NULL */
00017 /*@access FD_t@*/               /* XXX compared with NULL */
00018 
00024 static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
00025     if (this)   free((void *)this);
00026     return NULL;
00027 }
00028 
00029 char * RPMVERSION = VERSION;    /* just to put a marker in librpm.a */
00030 
00031 char ** splitString(const char * str, int length, char sep)
00032 {
00033     const char * source;
00034     char * s, * dest;
00035     char ** list;
00036     int i;
00037     int fields;
00038 
00039     s = xmalloc(length + 1);
00040 
00041     fields = 1;
00042     for (source = str, dest = s, i = 0; i < length; i++, source++, dest++) {
00043         *dest = *source;
00044         if (*dest == sep) fields++;
00045     }
00046 
00047     *dest = '\0';
00048 
00049     list = xmalloc(sizeof(char *) * (fields + 1));
00050 
00051     dest = s;
00052     list[0] = dest;
00053     i = 1;
00054     while (i < fields) {
00055         if (*dest == sep) {
00056             list[i++] = dest + 1;
00057             *dest = 0;
00058         }
00059         dest++;
00060     }
00061 
00062     list[i] = NULL;
00063 
00064     return list;
00065 }
00066 
00067 void freeSplitString(char ** list)
00068 {
00069     list[0] = _free(list[0]);
00070     list = _free(list);
00071 }
00072 
00073 int rpmfileexists(const char * urlfn)
00074 {
00075     const char *fn;
00076     int urltype = urlPath(urlfn, &fn);
00077     struct stat buf;
00078 
00079     if (*fn == '\0') fn = "/";
00080     switch (urltype) {
00081     case URL_IS_FTP:    /* XXX WRONG WRONG WRONG */
00082     case URL_IS_HTTP:   /* XXX WRONG WRONG WRONG */
00083     case URL_IS_PATH:
00084     case URL_IS_UNKNOWN:
00085         if (Stat(fn, &buf)) {
00086             switch(errno) {
00087             case ENOENT:
00088             case EINVAL:
00089                 return 0;
00090             }
00091         }
00092         break;
00093     case URL_IS_DASH:
00094     default:
00095         return 0;
00096         /*@notreached@*/ break;
00097     }
00098 
00099     return 1;
00100 }
00101 
00102 /* compare alpha and numeric segments of two versions */
00103 /* return 1: a is newer than b */
00104 /*        0: a and b are the same version */
00105 /*       -1: b is newer than a */
00106 int rpmvercmp(const char * a, const char * b)
00107 {
00108     char oldch1, oldch2;
00109     char * str1, * str2;
00110     char * one, * two;
00111     int rc;
00112     int isnum;
00113 
00114     /* easy comparison to see if versions are identical */
00115     if (!strcmp(a, b)) return 0;
00116 
00117     str1 = alloca(strlen(a) + 1);
00118     str2 = alloca(strlen(b) + 1);
00119 
00120     strcpy(str1, a);
00121     strcpy(str2, b);
00122 
00123     one = str1;
00124     two = str2;
00125 
00126     /* loop through each version segment of str1 and str2 and compare them */
00127     while (*one && *two) {
00128         while (*one && !isalnum(*one)) one++;
00129         while (*two && !isalnum(*two)) two++;
00130 
00131         str1 = one;
00132         str2 = two;
00133 
00134         /* grab first completely alpha or completely numeric segment */
00135         /* leave one and two pointing to the start of the alpha or numeric */
00136         /* segment and walk str1 and str2 to end of segment */
00137         if (isdigit(*str1)) {
00138             while (*str1 && isdigit(*str1)) str1++;
00139             while (*str2 && isdigit(*str2)) str2++;
00140             isnum = 1;
00141         } else {
00142             while (*str1 && isalpha(*str1)) str1++;
00143             while (*str2 && isalpha(*str2)) str2++;
00144             isnum = 0;
00145         }
00146 
00147         /* save character at the end of the alpha or numeric segment */
00148         /* so that they can be restored after the comparison */
00149         oldch1 = *str1;
00150         *str1 = '\0';
00151         oldch2 = *str2;
00152         *str2 = '\0';
00153 
00154         /* take care of the case where the two version segments are */
00155         /* different types: one numeric, the other alpha (i.e. empty) */
00156         if (one == str1) return -1;     /* arbitrary */
00157         if (two == str2) return 1;
00158 
00159         if (isnum) {
00160             /* this used to be done by converting the digit segments */
00161             /* to ints using atoi() - it's changed because long  */
00162             /* digit segments can overflow an int - this should fix that. */
00163 
00164             /* throw away any leading zeros - it's a number, right? */
00165             while (*one == '0') one++;
00166             while (*two == '0') two++;
00167 
00168             /* whichever number has more digits wins */
00169             if (strlen(one) > strlen(two)) return 1;
00170             if (strlen(two) > strlen(one)) return -1;
00171         }
00172 
00173         /* strcmp will return which one is greater - even if the two */
00174         /* segments are alpha or if they are numeric.  don't return  */
00175         /* if they are equal because there might be more segments to */
00176         /* compare */
00177         rc = strcmp(one, two);
00178         if (rc) return rc;
00179 
00180         /* restore character that was replaced by null above */
00181         *str1 = oldch1;
00182         one = str1;
00183         *str2 = oldch2;
00184         two = str2;
00185     }
00186 
00187     /* this catches the case where all numeric and alpha segments have */
00188     /* compared identically but the segment sepparating characters were */
00189     /* different */
00190     if ((!*one) && (!*two)) return 0;
00191 
00192     /* whichever version still has characters left over wins */
00193     if (!*one) return -1; else return 1;
00194 }
00195 
00196 int doputenv(const char *str)
00197 {
00198     char * a;
00199 
00200     /* FIXME: this leaks memory! */
00201 
00202     a = xmalloc(strlen(str) + 1);
00203     strcpy(a, str);
00204 
00205     return putenv(a);
00206 }
00207 
00208 int dosetenv(const char *name, const char *value, int overwrite)
00209 {
00210     int i;
00211     char * a;
00212 
00213     /* FIXME: this leaks memory! */
00214 
00215     if (!overwrite && getenv(name)) return 0;
00216 
00217     i = strlen(name) + strlen(value) + 2;
00218     a = xmalloc(i);
00219     if (!a) return 1;
00220 
00221     strcpy(a, name);
00222     strcat(a, "=");
00223     strcat(a, value);
00224 
00225     return putenv(a);
00226 }
00227 
00228 static int rpmMkpath(const char * path, mode_t mode, uid_t uid, gid_t gid)
00229 {
00230     char * d, * de;
00231     int created = 0;
00232     int rc;
00233 
00234     if (path == NULL)
00235         return -1;
00236     d = alloca(strlen(path)+2);
00237     de = stpcpy(d, path);
00238     de[1] = '\0';
00239     for (de = d; *de; de++) {
00240         struct stat st;
00241         char savec;
00242 
00243         while (*de && *de != '/') de++;
00244         savec = de[1];
00245         de[1] = '\0';
00246 
00247         rc = stat(d, &st);
00248         if (rc) {
00249             switch(errno) {
00250             default:
00251                 return errno;
00252                 /*@notreached@*/ break;
00253             case ENOENT:
00254                 break;
00255             }
00256             rc = mkdir(d, mode);
00257             if (rc)
00258                 return errno;
00259             created = 1;
00260             if (!(uid == (uid_t) -1 && gid == (gid_t) -1)) {
00261                 rc = chown(d, uid, gid);
00262                 if (rc)
00263                     return errno;
00264             }
00265         } else if (!S_ISDIR(st.st_mode)) {
00266             return ENOTDIR;
00267         }
00268         de[1] = savec;
00269     }
00270     rc = 0;
00271     if (created)
00272         rpmMessage(RPMMESS_WARNING, "created %%_tmppath directory %s\n", path);
00273     return rc;
00274 }
00275 
00276 int makeTempFile(const char * prefix, const char ** fnptr, FD_t * fdptr)
00277 {
00278     const char * tpmacro = "%{?_tmppath:%{_tmppath}}%{!?_tmppath:/var/tmp}";
00279     const char * tempfn = NULL;
00280     const char * tfn = NULL;
00281     static int _initialized = 0;
00282     int temput;
00283     FD_t fd = NULL;
00284     int ran;
00285 
00286     if (!prefix) prefix = "";
00287 
00288     /* Create the temp directory if it doesn't already exist. */
00289     if (!_initialized) {
00290         _initialized = 1;
00291         tempfn = rpmGenPath(prefix, tpmacro, NULL);
00292         if (rpmMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
00293             goto errxit;
00294     }
00295 
00296     /* XXX should probably use mkstemp here */
00297     srand(time(NULL));
00298     ran = rand() % 100000;
00299 
00300     /* maybe this should use link/stat? */
00301 
00302     do {
00303         char tfnbuf[64];
00304 #ifndef NOTYET
00305         sprintf(tfnbuf, "rpm-tmp.%d", ran++);
00306         tempfn = _free(tempfn);
00307         tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
00308 #else
00309         strcpy(tfnbuf, "rpm-tmp.XXXXXX");
00310         tempfn = _free(tempfn);
00311         tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
00312 #endif
00313 
00314         temput = urlPath(tempfn, &tfn);
00315         if (*tfn == '\0') goto errxit;
00316 
00317         switch (temput) {
00318         case URL_IS_HTTP:
00319         case URL_IS_DASH:
00320             goto errxit;
00321             /*@notreached@*/ break;
00322         default:
00323             break;
00324         }
00325 
00326         fd = Fopen(tempfn, "w+x.ufdio");
00327         /* XXX FIXME: errno may not be correct for ufdio */
00328     } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
00329 
00330     if (fd == NULL || Ferror(fd))
00331         goto errxit;
00332 
00333     switch(temput) {
00334         struct stat sb, sb2;
00335     case URL_IS_PATH:
00336     case URL_IS_UNKNOWN:
00337         if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
00338             rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
00339             goto errxit;
00340         }
00341 
00342         if (sb.st_nlink != 1) {
00343             rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
00344             goto errxit;
00345         }
00346 
00347         if (fstat(Fileno(fd), &sb2) == 0) {
00348             if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
00349                 rpmError(RPMERR_SCRIPT, _("error creating temporary file %s\n"), tfn);
00350                 goto errxit;
00351             }
00352         }
00353         break;
00354     default:
00355         break;
00356     }
00357 
00358     if (fnptr)
00359         *fnptr = tempfn;
00360     else 
00361         tempfn = _free(tempfn);
00362     *fdptr = fd;
00363 
00364     return 0;
00365 
00366 errxit:
00367     tempfn = _free(tempfn);
00368     if (fd) Fclose(fd);
00369     return 1;
00370 }
00371 
00372 char * currentDirectory(void)
00373 {
00374     int currDirLen;
00375     char * currDir;
00376 
00377     currDirLen = 50;
00378     currDir = xmalloc(currDirLen);
00379     while (!getcwd(currDir, currDirLen) && errno == ERANGE) {
00380         currDirLen += 50;
00381         currDir = xrealloc(currDir, currDirLen);
00382     }
00383 
00384     return currDir;
00385 }
00386 
00387 int _noDirTokens = 0;
00388 
00389 static int dncmp(const void * a, const void * b)
00390 {
00391     const char *const * first = a;
00392     const char *const * second = b;
00393     return strcmp(*first, *second);
00394 }
00395 
00396 void compressFilelist(Header h)
00397 {
00398     char ** fileNames;
00399     const char ** dirNames;
00400     const char ** baseNames;
00401     int_32 * dirIndexes;
00402     int fnt;
00403     int count;
00404     int i;
00405     int dirIndex = -1;
00406 
00407     /*
00408      * This assumes the file list is already sorted, and begins with a
00409      * single '/'. That assumption isn't critical, but it makes things go
00410      * a bit faster.
00411      */
00412 
00413     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00414         headerRemoveEntry(h, RPMTAG_OLDFILENAMES);
00415         return;         /* Already converted. */
00416     }
00417 
00418     if (!headerGetEntry(h, RPMTAG_OLDFILENAMES, &fnt,
00419                         (void **) &fileNames, &count))
00420         return;         /* no file list */
00421 
00422     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
00423     baseNames = alloca(sizeof(*dirNames) * count);
00424     dirIndexes = alloca(sizeof(*dirIndexes) * count);
00425 
00426     if (fileNames[0][0] != '/') {
00427         /* HACK. Source RPM, so just do things differently */
00428         dirIndex = 0;
00429         dirNames[dirIndex] = "";
00430         for (i = 0; i < count; i++) {
00431             dirIndexes[i] = dirIndex;
00432             baseNames[i] = fileNames[i];
00433         }
00434         goto exit;
00435     }
00436 
00437     for (i = 0; i < count; i++) {
00438         const char ** needle;
00439         char *baseName = strrchr(fileNames[i], '/') + 1;
00440         char savechar;
00441         int len = baseName - fileNames[i];
00442 
00443         savechar = *baseName;
00444         *baseName = '\0';
00445         if (dirIndex < 0 ||
00446             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00447             char *s = alloca(len + 1);
00448             memcpy(s, fileNames[i], len + 1);
00449             s[len] = '\0';
00450             dirIndexes[i] = ++dirIndex;
00451             dirNames[dirIndex] = s;
00452         } else
00453             dirIndexes[i] = needle - dirNames;
00454 
00455         *baseName = savechar;
00456         baseNames[i] = baseName;
00457     }
00458 
00459 exit:
00460     headerAddEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
00461                         dirIndexes, count);
00462     headerAddEntry(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00463                         baseNames, count);
00464     headerAddEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00465                         dirNames, dirIndex + 1);
00466 
00467     fileNames = headerFreeData(fileNames, fnt);
00468 
00469     headerRemoveEntry(h, RPMTAG_OLDFILENAMES);
00470 }
00471 
00472 /*
00473  * This is pretty straight-forward. The only thing that even resembles a trick
00474  * is getting all of this into a single xmalloc'd block.
00475  */
00476 static void doBuildFileList(Header h, /*@out@*/ const char *** fileListPtr,
00477                             /*@out@*/ int * fileCountPtr, int baseNameTag,
00478                             int dirNameTag, int dirIndexesTag)
00479 {
00480     const char ** baseNames;
00481     const char ** dirNames;
00482     int * dirIndexes;
00483     int count;
00484     const char ** fileNames;
00485     int size;
00486     int bnt, dnt;
00487     char * data;
00488     int i;
00489 
00490     if (!headerGetEntry(h, baseNameTag, &bnt, (void **) &baseNames, &count)) {
00491         if (fileListPtr) *fileListPtr = NULL;
00492         if (fileCountPtr) *fileCountPtr = 0;
00493         return;         /* no file list */
00494     }
00495 
00496     headerGetEntry(h, dirNameTag, &dnt, (void **) &dirNames, NULL);
00497     headerGetEntry(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
00498 
00499     size = sizeof(*fileNames) * count;
00500     for (i = 0; i < count; i++)
00501         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
00502 
00503     fileNames = xmalloc(size);
00504     data = ((char *) fileNames) + (sizeof(*fileNames) * count);
00505     for (i = 0; i < count; i++) {
00506         fileNames[i] = data;
00507         data = stpcpy( stpcpy(data, dirNames[dirIndexes[i]]), baseNames[i]);
00508         *data++ = '\0';
00509     }
00510     baseNames = headerFreeData(baseNames, bnt);
00511     dirNames = headerFreeData(dirNames, dnt);
00512 
00513     if (fileListPtr)
00514         *fileListPtr = fileNames;
00515     else
00516         fileNames = _free(fileNames);
00517     if (fileCountPtr) *fileCountPtr = count;
00518 }
00519 
00520 void expandFilelist(Header h)
00521 {
00522     const char ** fileNames = NULL;
00523     int count = 0;
00524 
00525     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
00526         doBuildFileList(h, &fileNames, &count, RPMTAG_BASENAMES,
00527                         RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES);
00528         if (fileNames == NULL || count <= 0)
00529             return;
00530         headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00531                         fileNames, count);
00532         fileNames = _free(fileNames);
00533     }
00534 
00535     headerRemoveEntry(h, RPMTAG_DIRNAMES);
00536     headerRemoveEntry(h, RPMTAG_BASENAMES);
00537     headerRemoveEntry(h, RPMTAG_DIRINDEXES);
00538 }
00539 
00540 
00541 void rpmBuildFileList(Header h, const char *** fileListPtr, int * fileCountPtr)
00542 {
00543     doBuildFileList(h, fileListPtr, fileCountPtr, RPMTAG_BASENAMES,
00544                         RPMTAG_DIRNAMES, RPMTAG_DIRINDEXES);
00545 }
00546 
00547 void buildOrigFileList(Header h, const char *** fileListPtr, int * fileCountPtr)
00548 {
00549     doBuildFileList(h, fileListPtr, fileCountPtr, RPMTAG_ORIGBASENAMES,
00550                         RPMTAG_ORIGDIRNAMES, RPMTAG_ORIGDIRINDEXES);
00551 }
00552 
00553 /* glob_pattern_p() taken from bash
00554  * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
00555  *
00556  * Return nonzero if PATTERN has any special globbing chars in it.
00557  */
00558 int myGlobPatternP (const char *patternURL)
00559 {
00560     const char *p;
00561     char c;
00562     int open = 0;
00563   
00564     (void) urlPath(patternURL, &p);
00565     while ((c = *p++) != '\0')
00566         switch (c) {
00567         case '?':
00568         case '*':
00569             return (1);
00570         case '[':      /* Only accept an open brace if there is a close */
00571             open++;    /* brace to match it.  Bracket expressions must be */
00572             continue;  /* complete, according to Posix.2 */
00573         case ']':
00574             if (open)
00575                 return (1);
00576             continue;      
00577         case '\\':
00578             if (*p++ == '\0')
00579                 return (0);
00580         }
00581 
00582     return (0);
00583 }
00584 
00585 static int glob_error(/*@unused@*/const char *foo, /*@unused@*/int bar)
00586 {
00587     return 1;
00588 }
00589 
00590 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
00591 {
00592     int ac = 0;
00593     const char ** av = NULL;
00594     int argc = 0;
00595     const char ** argv = NULL;
00596     const char * path;
00597     const char * globURL;
00598     char * globRoot = NULL;
00599     size_t maxb, nb;
00600     glob_t gl;
00601     int ut;
00602     int i, j;
00603     int rc;
00604 
00605     rc = poptParseArgvString(patterns, &ac, &av);
00606     if (rc)
00607         return rc;
00608 
00609     for (j = 0; j < ac; j++) {
00610         if (!myGlobPatternP(av[j])) {
00611             if (argc == 0)
00612                 argv = xmalloc((argc+2) * sizeof(*argv));
00613             else
00614                 argv = xrealloc(argv, (argc+2) * sizeof(*argv));
00615             argv[argc] = xstrdup(av[j]);
00616 if (_debug)
00617 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]);
00618             argc++;
00619             continue;
00620         }
00621         
00622         gl.gl_pathc = 0;
00623         gl.gl_pathv = NULL;
00624         rc = Glob(av[j], 0, glob_error, &gl);
00625         if (rc)
00626             goto exit;
00627 
00628         /* XXX Prepend the URL leader for globs that have stripped it off */
00629         maxb = 0;
00630         for (i = 0; i < gl.gl_pathc; i++) {
00631             if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
00632                 maxb = nb;
00633         }
00634         
00635         ut = urlPath(av[j], &path);
00636         nb = ((ut > URL_IS_DASH) ? (path - av[j]) : 0);
00637         maxb += nb;
00638         maxb += 1;
00639         globURL = globRoot = xmalloc(maxb);
00640 
00641         switch (ut) {
00642         case URL_IS_HTTP:
00643         case URL_IS_FTP:
00644         case URL_IS_PATH:
00645         case URL_IS_DASH:
00646             strncpy(globRoot, av[j], nb);
00647             break;
00648         case URL_IS_UNKNOWN:
00649             break;
00650         }
00651         globRoot += nb;
00652         *globRoot = '\0';
00653 if (_debug)
00654 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
00655         
00656         if (argc == 0)
00657             argv = xmalloc((gl.gl_pathc+1) * sizeof(*argv));
00658         else if (gl.gl_pathc > 0)
00659             argv = xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
00660         for (i = 0; i < gl.gl_pathc; i++) {
00661             const char * globFile = &(gl.gl_pathv[i][0]);
00662             if (globRoot > globURL && globRoot[-1] == '/')
00663                 while (*globFile == '/') globFile++;
00664             strcpy(globRoot, globFile);
00665 if (_debug)
00666 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
00667             argv[argc++] = xstrdup(globURL);
00668         }
00669         Globfree(&gl);
00670         globURL = _free(globURL);
00671     }
00672     if (argv != NULL && argc > 0) {
00673         argv[argc] = NULL;
00674         if (argvPtr)
00675             *argvPtr = argv;
00676         if (argcPtr)
00677             *argcPtr = argc;
00678         rc = 0;
00679     } else
00680         rc = 1;
00681 
00682 
00683 exit:
00684     av = _free(av);
00685     if ((rc || argvPtr == NULL) && argv) {
00686         for (i = 0; i < argc; i++)
00687             argv[i] = _free(argv[i]);
00688         argv = _free(argv);
00689     }
00690     return rc;
00691 }
00692 
00693 /*
00694  * XXX This is a "dressed" entry to headerGetEntry to do:
00695  *      1) DIRNAME/BASENAME/DIRINDICES -> FILENAMES tag conversions.
00696  *      2) i18n lookaside (if enabled).
00697  */
00698 int rpmHeaderGetEntry(Header h, int_32 tag, int_32 *type,
00699         void **p, int_32 *c)
00700 {
00701     switch (tag) {
00702     case RPMTAG_OLDFILENAMES:
00703     {   const char ** fl = NULL;
00704         int count;
00705         rpmBuildFileList(h, &fl, &count);
00706         if (count > 0) {
00707             *p = fl;
00708             if (c)      *c = count;
00709             if (type)   *type = RPM_STRING_ARRAY_TYPE;
00710             return 1;
00711         }
00712         if (c)  *c = 0;
00713         return 0;
00714     }   /*@notreached@*/ break;
00715 
00716     case RPMTAG_GROUP:
00717     case RPMTAG_DESCRIPTION:
00718     case RPMTAG_SUMMARY:
00719     {   char fmt[128];
00720         const char * msgstr;
00721         const char * errstr;
00722 
00723         fmt[0] = '\0';
00724         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tagName(tag)), "}\n");
00725 
00726         /* XXX FIXME: memory leak. */
00727         msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
00728         if (msgstr) {
00729             *p = (void *) msgstr;
00730             if (type)   *type = RPM_STRING_TYPE;
00731             if (c)      *c = 1;
00732             return 1;
00733         } else {
00734             if (c)      *c = 0;
00735             return 0;
00736         }
00737     }   /*@notreached@*/ break;
00738 
00739     default:
00740         return headerGetEntry(h, tag, type, p, c);
00741         /*@notreached@*/ break;
00742     }
00743     /*@notreached@*/
00744 }
00745 
00746 /*
00747  * XXX Yet Another dressed entry to unify signature/header tag retrieval.
00748  */
00749 int rpmPackageGetEntry( /*@unused@*/ void *leadp, Header sigs, Header h,
00750         int_32 tag, int_32 *type, void **p, int_32 *c)
00751 {
00752     int_32 sigtag;
00753 
00754     switch (tag) {
00755     case RPMTAG_SIGSIZE:        sigtag = RPMSIGTAG_SIZE;        break;
00756     case RPMTAG_SIGLEMD5_1:     sigtag = RPMSIGTAG_LEMD5_1;     break;
00757     case RPMTAG_SIGPGP:         sigtag = RPMSIGTAG_PGP;         break;
00758     case RPMTAG_SIGLEMD5_2:     sigtag = RPMSIGTAG_LEMD5_2;     break;
00759     case RPMTAG_SIGMD5:         sigtag = RPMSIGTAG_MD5;         break;
00760     case RPMTAG_SIGGPG:         sigtag = RPMSIGTAG_GPG;         break;
00761     case RPMTAG_SIGPGP5:        sigtag = RPMSIGTAG_GPG;         break;
00762         
00763     default:
00764         return rpmHeaderGetEntry(h, tag, type, p, c);
00765         /*@notreached@*/ break;
00766     }
00767 
00768     if (headerIsEntry(h, tag))
00769         return rpmHeaderGetEntry(h, tag, type, p, c);
00770 
00771     if (sigs == NULL) {
00772         if (c)  *c = 0;
00773         return 0;
00774     }
00775 
00776     return headerGetEntry(sigs, sigtag, type, p, c);
00777 }
00778 
00779 /*
00780  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
00781  * Retrofit an explicit "Provides: name = epoch:version-release.
00782  */
00783 void providePackageNVR(Header h)
00784 {
00785     const char *name, *version, *release;
00786     int_32 * epoch;
00787     const char *pEVR;
00788     char *p;
00789     int_32 pFlags = RPMSENSE_EQUAL;
00790     const char ** provides = NULL;
00791     const char ** providesEVR = NULL;
00792     int_32 * provideFlags = NULL;
00793     int providesCount;
00794     int i;
00795     int bingo = 1;
00796 
00797     /* Generate provides for this package name-version-release. */
00798     headerNVR(h, &name, &version, &release);
00799     pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00800     *p = '\0';
00801     if (headerGetEntry(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00802         sprintf(p, "%d:", *epoch);
00803         while (*p)
00804             p++;
00805     }
00806     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00807 
00808     /*
00809      * Rpm prior to 3.0.3 does not have versioned provides.
00810      * If no provides at all are available, we can just add.
00811      */
00812     if (!headerGetEntry(h, RPMTAG_PROVIDENAME, NULL,
00813                 (void **) &provides, &providesCount)) {
00814         goto exit;
00815     }
00816 
00817     /*
00818      * Otherwise, fill in entries on legacy packages.
00819      */
00820     if (!headerGetEntry(h, RPMTAG_PROVIDEVERSION, NULL,
00821                 (void **) &providesEVR, NULL)) {
00822         for (i = 0; i < providesCount; i++) {
00823             char * vdummy = "";
00824             int_32 fdummy = RPMSENSE_ANY;
00825             headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00826                         &vdummy, 1);
00827             headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00828                         &fdummy, 1);
00829         }
00830         goto exit;
00831     }
00832 
00833     headerGetEntry(h, RPMTAG_PROVIDEFLAGS, NULL,
00834         (void **) &provideFlags, NULL);
00835 
00836     for (i = 0; i < providesCount; i++) {
00837         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00838             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00839             continue;
00840         bingo = 0;
00841         break;
00842     }
00843 
00844 exit:
00845     provides = headerFreeData(provides, -1);
00846     providesEVR = headerFreeData(providesEVR, -1);
00847 
00848     if (bingo) {
00849         headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00850                 &name, 1);
00851         headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00852                 &pFlags, 1);
00853         headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00854                 &pEVR, 1);
00855     }
00856 }

Generated at Thu Apr 19 15:29:41 2001 for rpm by doxygen1.2.6-20010408 written by Dimitri van Heesch, © 1997-2001