# lib/misc.c

Go to the documentation of this file.

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