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

Generated on Wed Mar 13 15:34:46 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002