• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

lib/rpmfi.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio.h>
00009 #include <rpmcb.h>              /* XXX fnpyKey */
00010 #include <rpmurl.h>     /* XXX urlGetPath */
00011 #include <rpmlib.h>
00012 
00013 #include "cpio.h"       /* XXX CPIO_FOO */
00014 #define _RPMFI_INTERNAL
00015 #include "fsm.h"        /* XXX newFSM() */
00016 #include "legacy.h"     /* XXX dodigest */
00017 
00018 #include "rpmds.h"
00019 
00020 #define _RPMTE_INTERNAL /* relocations */
00021 #include "rpmte.h"
00022 #include "rpmts.h"
00023 
00024 #include "misc.h"       /* XXX stripTrailingChar */
00025 #include "rpmmacro.h"   /* XXX rpmCleanPath */
00026 
00027 #include "debug.h"
00028 
00029 /*@access rpmte @*/
00030 /*@access FSM_t @*/     /* XXX fsm->repackaged */
00031 
00032 /*@unchecked@*/
00033 int _rpmfi_debug = 0;
00034 
00035 rpmfi XrpmfiUnlink(rpmfi fi, const char * msg, const char * fn, unsigned ln)
00036 {
00037     if (fi == NULL) return NULL;
00038 /*@-modfilesys@*/
00039 if (_rpmfi_debug && msg != NULL)
00040 fprintf(stderr, "--> fi %p -- %d %s at %s:%u\n", fi, fi->nrefs, msg, fn, ln);
00041 /*@=modfilesys@*/
00042     fi->nrefs--;
00043     return NULL;
00044 }
00045 
00046 rpmfi XrpmfiLink(rpmfi fi, const char * msg, const char * fn, unsigned ln)
00047 {
00048     if (fi == NULL) return NULL;
00049     fi->nrefs++;
00050 /*@-modfilesys@*/
00051 if (_rpmfi_debug && msg != NULL)
00052 fprintf(stderr, "--> fi %p ++ %d %s at %s:%u\n", fi, fi->nrefs, msg, fn, ln);
00053 /*@=modfilesys@*/
00054     /*@-refcounttrans@*/ return fi; /*@=refcounttrans@*/
00055 }
00056 
00057 int rpmfiFC(rpmfi fi)
00058 {
00059     return (fi != NULL ? fi->fc : 0);
00060 }
00061 
00062 int rpmfiDC(rpmfi fi)
00063 {
00064     return (fi != NULL ? fi->dc : 0);
00065 }
00066 
00067 #ifdef  NOTYET
00068 int rpmfiDI(rpmfi fi)
00069 {
00070 }
00071 #endif
00072 
00073 int rpmfiFX(rpmfi fi)
00074 {
00075     return (fi != NULL ? fi->i : -1);
00076 }
00077 
00078 int rpmfiSetFX(rpmfi fi, int fx)
00079 {
00080     int i = -1;
00081 
00082     if (fi != NULL && fx >= 0 && fx < fi->fc) {
00083         i = fi->i;
00084         fi->i = fx;
00085         fi->j = fi->dil[fi->i];
00086     }
00087     return i;
00088 }
00089 
00090 int rpmfiDX(rpmfi fi)
00091 {
00092     return (fi != NULL ? fi->j : -1);
00093 }
00094 
00095 int rpmfiSetDX(rpmfi fi, int dx)
00096 {
00097     int j = -1;
00098 
00099     if (fi != NULL && dx >= 0 && dx < fi->dc) {
00100         j = fi->j;
00101         fi->j = dx;
00102     }
00103     return j;
00104 }
00105 
00106 int rpmfiIsSource(rpmfi fi)
00107 {
00108     return (fi != NULL ? fi->isSource : 0);
00109 }
00110 
00111 const char * rpmfiBN(rpmfi fi)
00112 {
00113     const char * BN = NULL;
00114 
00115     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00116         if (fi->bnl != NULL)
00117             BN = fi->bnl[fi->i];
00118     }
00119     return BN;
00120 }
00121 
00122 const char * rpmfiDN(rpmfi fi)
00123 {
00124     const char * DN = NULL;
00125 
00126     if (fi != NULL && fi->j >= 0 && fi->j < fi->dc) {
00127         if (fi->dnl != NULL)
00128             DN = fi->dnl[fi->j];
00129     }
00130     return DN;
00131 }
00132 
00133 const char * rpmfiFN(rpmfi fi)
00134 {
00135     const char * FN = "";
00136 
00137     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00138         const char *dn;
00139         char * t;
00140         if (fi->fn == NULL)
00141             fi->fn = xmalloc(fi->fnlen);
00142         FN = t = fi->fn;
00143         (void) urlPath(fi->dnl[fi->dil[fi->i]], &dn);
00144         *t = '\0';
00145         t = stpcpy(t, dn);
00146         t = stpcpy(t, fi->bnl[fi->i]);
00147     }
00148     return FN;
00149 }
00150 
00151 uint32_t rpmfiFFlags(rpmfi fi)
00152 {
00153     uint32_t FFlags = 0;
00154 
00155     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00156         if (fi->fflags != NULL)
00157             FFlags = fi->fflags[fi->i];
00158     }
00159     return FFlags;
00160 }
00161 
00162 uint32_t rpmfiSetFFlags(rpmfi fi, uint32_t FFlags)
00163 {
00164     uint32_t oFFlags = 0;
00165 
00166     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00167         if (fi->fflags != NULL && fi->h == NULL) {
00168             oFFlags = fi->fflags[fi->i];
00169             *((uint32_t *)(fi->fflags + fi->i)) = FFlags;
00170         }
00171     }
00172     return oFFlags;
00173 }
00174 
00175 uint32_t rpmfiVFlags(rpmfi fi)
00176 {
00177     uint32_t VFlags = 0;
00178 
00179     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00180         if (fi->vflags != NULL)
00181             VFlags = fi->vflags[fi->i];
00182     }
00183     return VFlags;
00184 }
00185 
00186 uint32_t rpmfiSetVFlags(rpmfi fi, uint32_t VFlags)
00187 {
00188     uint32_t oVFlags = 0;
00189 
00190     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00191         if (fi->vflags != NULL && fi->h == NULL) {
00192             oVFlags = fi->vflags[fi->i];
00193             *((uint32_t *)(fi->vflags + fi->i)) = VFlags;
00194         }
00195     }
00196     return oVFlags;
00197 }
00198 
00199 uint16_t rpmfiFMode(rpmfi fi)
00200 {
00201     uint16_t fmode = 0;
00202 
00203     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00204         if (fi->fmodes != NULL)
00205             fmode = fi->fmodes[fi->i];
00206     }
00207     return fmode;
00208 }
00209 
00210 rpmfileState rpmfiFState(rpmfi fi)
00211 {
00212     rpmfileState fstate = RPMFILE_STATE_MISSING;
00213 
00214     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00215         if (fi->fstates != NULL)
00216             fstate = fi->fstates[fi->i];
00217     }
00218     return fstate;
00219 }
00220 
00221 rpmfileState rpmfiSetFState(rpmfi fi, rpmfileState fstate)
00222 {
00223     uint32_t ofstate = 0;
00224 
00225     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00226         if (fi->fstates != NULL) {
00227             ofstate = fi->fstates[fi->i];
00228             fi->fstates[fi->i] = fstate;
00229         }
00230     }
00231     return ofstate;
00232 }
00233 
00234 const unsigned char * rpmfiDigest(rpmfi fi, int * algop, size_t * lenp)
00235 {
00236     unsigned char * digest = NULL;
00237 
00238     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00239         if (fi->digests != NULL) {
00240             digest = fi->digests + (fi->digestlen * fi->i);
00241             if (algop != NULL)
00242                 *algop = (fi->fdigestalgos
00243                         ? fi->fdigestalgos[fi->i] : fi->digestalgo);
00244             if (lenp != NULL)
00245                 *lenp = fi->digestlen;
00246         }
00247     }
00248     return digest;
00249 }
00250 
00251 const char * rpmfiFLink(rpmfi fi)
00252 {
00253     const char * flink = NULL;
00254 
00255     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00256         if (fi->flinks != NULL)
00257             flink = fi->flinks[fi->i];
00258     }
00259     return flink;
00260 }
00261 
00262 uint32_t rpmfiFSize(rpmfi fi)
00263 {
00264     uint32_t fsize = 0;
00265 
00266     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00267         if (fi->fsizes != NULL)
00268             fsize = fi->fsizes[fi->i];
00269     }
00270     return fsize;
00271 }
00272 
00273 uint16_t rpmfiFRdev(rpmfi fi)
00274 {
00275     uint16_t frdev = 0;
00276 
00277     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00278         if (fi->frdevs != NULL)
00279             frdev = fi->frdevs[fi->i];
00280     }
00281     return frdev;
00282 }
00283 
00284 uint32_t rpmfiFInode(rpmfi fi)
00285 {
00286     uint32_t finode = 0;
00287 
00288     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00289         if (fi->finodes != NULL)
00290             finode = fi->finodes[fi->i];
00291     }
00292     return finode;
00293 }
00294 
00295 uint32_t rpmfiColor(rpmfi fi)
00296 {
00297     uint32_t color = 0;
00298 
00299     if (fi != NULL)
00300         /* XXX ignore all but lsnibble for now. */
00301         color = fi->color & 0xf;
00302     return color;
00303 }
00304 
00305 uint32_t rpmfiFColor(rpmfi fi)
00306 {
00307     uint32_t fcolor = 0;
00308 
00309     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00310         if (fi->fcolors != NULL)
00311             /* XXX ignore all but lsnibble for now. */
00312             fcolor = (fi->fcolors[fi->i] & 0x0f);
00313     }
00314     return fcolor;
00315 }
00316 
00317 const char * rpmfiFClass(rpmfi fi)
00318 {
00319     const char * fclass = NULL;
00320     int cdictx;
00321 
00322     if (fi != NULL && fi->fcdictx != NULL && fi->i >= 0 && fi->i < fi->fc) {
00323         cdictx = fi->fcdictx[fi->i];
00324         if (fi->cdict != NULL && cdictx >= 0 && cdictx < fi->ncdict)
00325             fclass = fi->cdict[cdictx];
00326     }
00327     return fclass;
00328 }
00329 
00330 const char * rpmfiFContext(rpmfi fi)
00331 {
00332     const char * fcontext = NULL;
00333 
00334     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00335         if (fi->fcontexts != NULL)
00336             fcontext = fi->fcontexts[fi->i];
00337     }
00338     return fcontext;
00339 }
00340 
00341 uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
00342 {
00343     int fddictx = -1;
00344     int fddictn = 0;
00345     const uint32_t * fddict = NULL;
00346 
00347     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00348         if (fi->fddictn != NULL)
00349             fddictn = fi->fddictn[fi->i];
00350         if (fddictn > 0 && fi->fddictx != NULL)
00351             fddictx = fi->fddictx[fi->i];
00352         if (fi->ddict != NULL && fddictx >= 0 && (fddictx+fddictn) <= fi->nddict)
00353             fddict = fi->ddict + fddictx;
00354     }
00355 /*@-dependenttrans -onlytrans @*/
00356     if (fddictp)
00357         *fddictp = fddict;
00358 /*@=dependenttrans =onlytrans @*/
00359     return fddictn;
00360 }
00361 
00362 uint32_t rpmfiFNlink(rpmfi fi)
00363 {
00364     uint32_t nlink = 0;
00365 
00366     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00367         /* XXX rpm-2.3.12 has not RPMTAG_FILEINODES */
00368         if (fi->finodes && fi->frdevs) {
00369             uint32_t finode = fi->finodes[fi->i];
00370             uint16_t frdev = fi->frdevs[fi->i];
00371             int j;
00372 
00373             for (j = 0; j < fi->fc; j++) {
00374                 if (fi->frdevs[j] == frdev && fi->finodes[j] == finode)
00375                     nlink++;
00376             }
00377         }
00378     }
00379     return nlink;
00380 }
00381 
00382 uint32_t rpmfiFMtime(rpmfi fi)
00383 {
00384     uint32_t fmtime = 0;
00385 
00386     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00387         if (fi->fmtimes != NULL)
00388             fmtime = fi->fmtimes[fi->i];
00389     }
00390     return fmtime;
00391 }
00392 
00393 const char * rpmfiFUser(rpmfi fi)
00394 {
00395     const char * fuser = NULL;
00396 
00397     /* XXX add support for ancient RPMTAG_FILEUIDS? */
00398     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00399         if (fi->fuser != NULL)
00400             fuser = fi->fuser[fi->i];
00401     }
00402     return fuser;
00403 }
00404 
00405 const char * rpmfiFGroup(rpmfi fi)
00406 {
00407     const char * fgroup = NULL;
00408 
00409     /* XXX add support for ancient RPMTAG_FILEGIDS? */
00410     if (fi != NULL && fi->i >= 0 && fi->i < fi->fc) {
00411         if (fi->fgroup != NULL)
00412             fgroup = fi->fgroup[fi->i];
00413     }
00414     return fgroup;
00415 }
00416 
00417 int rpmfiNext(rpmfi fi)
00418 {
00419     int i = -1;
00420 
00421     if (fi != NULL && ++fi->i >= 0) {
00422         if (fi->i < fi->fc) {
00423             i = fi->i;
00424             if (fi->dil != NULL)
00425                 fi->j = fi->dil[fi->i];
00426         } else
00427             fi->i = -1;
00428 
00429 /*@-modfilesys @*/
00430 if (_rpmfi_debug  < 0 && i != -1)
00431 fprintf(stderr, "*** fi %p\t%s[%d] %s%s\n", fi, (fi->Type ? fi->Type : "?Type?"), i, (i >= 0 ? fi->dnl[fi->j] : ""), (i >= 0 ? fi->bnl[fi->i] : ""));
00432 /*@=modfilesys @*/
00433 
00434     }
00435 
00436     return i;
00437 }
00438 
00439 rpmfi rpmfiInit(rpmfi fi, int fx)
00440 {
00441     if (fi != NULL) {
00442         if (fx >= 0 && fx < fi->fc) {
00443             fi->i = fx - 1;
00444             fi->j = -1;
00445         }
00446     }
00447 
00448     /*@-refcounttrans@*/
00449     return fi;
00450     /*@=refcounttrans@*/
00451 }
00452 
00453 int rpmfiNextD(rpmfi fi)
00454 {
00455     int j = -1;
00456 
00457     if (fi != NULL && ++fi->j >= 0) {
00458         if (fi->j < fi->dc)
00459             j = fi->j;
00460         else
00461             fi->j = -1;
00462 
00463 /*@-modfilesys @*/
00464 if (_rpmfi_debug  < 0 && j != -1)
00465 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, (fi->Type ? fi->Type : "?Type?"), j);
00466 /*@=modfilesys @*/
00467 
00468     }
00469 
00470     return j;
00471 }
00472 
00473 rpmfi rpmfiInitD(rpmfi fi, int dx)
00474 {
00475     if (fi != NULL) {
00476         if (dx >= 0 && dx < fi->fc)
00477             fi->j = dx - 1;
00478         else
00479             fi = NULL;
00480     }
00481 
00482     /*@-refcounttrans@*/
00483     return fi;
00484     /*@=refcounttrans@*/
00485 }
00486 
00492 static /*@observer@*/
00493 const char * rpmfiFtstring (rpmFileTypes ft)
00494         /*@*/
00495 {
00496     switch (ft) {
00497     case XDIR:  return "directory";
00498     case CDEV:  return "char dev";
00499     case BDEV:  return "block dev";
00500     case LINK:  return "link";
00501     case SOCK:  return "sock";
00502     case PIPE:  return "fifo/pipe";
00503     case REG:   return "file";
00504     default:    return "unknown file type";
00505     }
00506     /*@notreached@*/
00507 }
00508 
00514 static rpmFileTypes rpmfiWhatis(uint16_t mode)
00515         /*@*/
00516 {
00517     if (S_ISDIR(mode))  return XDIR;
00518     if (S_ISCHR(mode))  return CDEV;
00519     if (S_ISBLK(mode))  return BDEV;
00520     if (S_ISLNK(mode))  return LINK;
00521 /*@-unrecog@*/
00522     if (S_ISSOCK(mode)) return SOCK;
00523 /*@=unrecog@*/
00524     if (S_ISFIFO(mode)) return PIPE;
00525     return REG;
00526 }
00527 
00528 int rpmfiCompare(const rpmfi afi, const rpmfi bfi)
00529         /*@*/
00530 {
00531     rpmFileTypes awhat = rpmfiWhatis(rpmfiFMode(afi));
00532     rpmFileTypes bwhat = rpmfiWhatis(rpmfiFMode(bfi));
00533 
00534     if (awhat != bwhat) return 1;
00535 
00536     if (awhat == LINK) {
00537         const char * alink = rpmfiFLink(afi);
00538         const char * blink = rpmfiFLink(bfi);
00539         if (alink == blink) return 0;
00540         if (alink == NULL) return 1;
00541         if (blink == NULL) return -1;
00542         return strcmp(alink, blink);
00543     } else if (awhat == REG) {
00544         int aalgo = 0;
00545         size_t alen = 0;
00546         const unsigned char * adigest = rpmfiDigest(afi, &aalgo, &alen);
00547         int balgo = 0;
00548         size_t blen = 0;
00549         const unsigned char * bdigest = rpmfiDigest(bfi, &balgo, &blen);
00550         /* XXX W2DO? changing file digest algo may break rpmfiCompare. */
00551         if (!(aalgo == balgo && alen == blen))
00552             return -1;
00553         if (adigest == bdigest) return 0;
00554         if (adigest == NULL) return 1;
00555         if (bdigest == NULL) return -1;
00556         return memcmp(adigest, bdigest, alen);
00557     }
00558 
00559     return 0;
00560 }
00561 
00562 fileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
00563 {
00564     const char * fn = rpmfiFN(nfi);
00565     int newFlags = rpmfiFFlags(nfi);
00566     char buffer[1024+1];
00567     rpmFileTypes dbWhat, newWhat, diskWhat;
00568     struct stat sb;
00569     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
00570 
00571     if (Lstat(fn, &sb)) {
00572         /*
00573          * The file doesn't exist on the disk. Create it unless the new
00574          * package has marked it as missingok, or allfiles is requested.
00575          */
00576         if (skipMissing && (newFlags & RPMFILE_MISSINGOK)) {
00577             rpmlog(RPMLOG_DEBUG, D_("%s skipped due to missingok flag\n"),
00578                         fn);
00579             return FA_SKIP;
00580         } else {
00581             return FA_CREATE;
00582         }
00583     }
00584 
00585     diskWhat = rpmfiWhatis((uint16_t)sb.st_mode);
00586     dbWhat = rpmfiWhatis(rpmfiFMode(ofi));
00587     newWhat = rpmfiWhatis(rpmfiFMode(nfi));
00588 
00589     /*
00590      * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
00591      * them in older packages as well.
00592      */
00593     if (newWhat == XDIR)
00594         return FA_CREATE;
00595 
00596     if (diskWhat != newWhat && dbWhat != REG && dbWhat != LINK)
00597         return save;
00598     else if (newWhat != dbWhat && diskWhat != dbWhat)
00599         return save;
00600     else if (dbWhat != newWhat)
00601         return FA_CREATE;
00602     else if (dbWhat != LINK && dbWhat != REG)
00603         return FA_CREATE;
00604 
00605     /*
00606      * This order matters - we'd prefer to CREATE the file if at all
00607      * possible in case something else (like the timestamp) has changed.
00608      */
00609     memset(buffer, 0, sizeof(buffer));
00610     if (dbWhat == REG) {
00611         int oalgo = 0;
00612         size_t olen = 0;
00613         const unsigned char * odigest;
00614         int nalgo = 0;
00615         size_t nlen = 0;
00616         const unsigned char * ndigest;
00617         odigest = rpmfiDigest(ofi, &oalgo, &olen);
00618         if (diskWhat == REG) {
00619             if (!(newFlags & RPMFILE_SPARSE))
00620             if (dodigest(oalgo, fn, (unsigned char *)buffer, 0, NULL))
00621                 return FA_CREATE;       /* assume file has been removed */
00622             if (odigest && !memcmp(odigest, buffer, olen))
00623                 return FA_CREATE;       /* unmodified config file, replace. */
00624         }
00625         ndigest = rpmfiDigest(nfi, &nalgo, &nlen);
00626 /*@-nullpass@*/
00627         if (odigest && ndigest && oalgo == nalgo && olen == nlen
00628          && !memcmp(odigest, ndigest, nlen))
00629             return FA_SKIP;     /* identical file, don't bother. */
00630 /*@=nullpass@*/
00631     } else /* dbWhat == LINK */ {
00632         const char * oFLink, * nFLink;
00633         oFLink = rpmfiFLink(ofi);
00634         if (diskWhat == LINK) {
00635             if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
00636                 return FA_CREATE;       /* assume file has been removed */
00637             buffer[sizeof(buffer)-1] = '\0';
00638             if (oFLink && !strcmp(oFLink, buffer))
00639                 return FA_CREATE;       /* unmodified config file, replace. */
00640         }
00641         nFLink = rpmfiFLink(nfi);
00642 /*@-nullpass@*/
00643         if (oFLink && nFLink && !strcmp(oFLink, nFLink))
00644             return FA_SKIP;     /* identical file, don't bother. */
00645 /*@=nullpass@*/
00646     }
00647 
00648     /*
00649      * The config file on the disk has been modified, but
00650      * the ones in the two packages are different. It would
00651      * be nice if RPM was smart enough to at least try and
00652      * merge the difference ala CVS, but...
00653      */
00654     return save;
00655 }
00656 
00657 /*@observer@*/
00658 const char * rpmfiTypeString(rpmfi fi)
00659 {
00660     switch(rpmteType(fi->te)) {
00661     case TR_ADDED:      return " install";
00662     case TR_REMOVED:    return "   erase";
00663     default:            return "???";
00664     }
00665     /*@noteached@*/
00666 }
00667 
00668 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00669 
00679 static
00680 Header relocateFileList(const rpmts ts, rpmfi fi,
00681                 Header origH, fileAction * actions)
00682         /*@globals rpmGlobalMacroContext, h_errno,
00683                 internalState @*/
00684         /*@modifies ts, fi, origH, actions, rpmGlobalMacroContext,
00685                 internalState @*/
00686 {
00687     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00688     rpmte p = rpmtsRelocateElement(ts);
00689     static int _printed = 0;
00690     int allowBadRelocate = (rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE);
00691     rpmRelocation relocations = NULL;
00692     int numRelocations;
00693     const char ** validRelocations;
00694     rpmTagType validType;
00695     int numValid;
00696     const char ** baseNames;
00697     const char ** dirNames;
00698     uint32_t * dirIndexes;
00699     uint32_t fileCount;
00700     uint32_t dirCount;
00701     uint32_t mydColor = rpmExpandNumeric("%{?_autorelocate_dcolor}");
00702     uint32_t * fFlags = NULL;
00703     uint32_t * fColors = NULL;
00704     uint32_t * dColors = NULL;
00705     uint16_t * fModes = NULL;
00706     Header h;
00707     int nrelocated = 0;
00708     int fileAlloced = 0;
00709     char * fn = NULL;
00710     int haveRelocatedFile = 0;
00711     int reldel = 0;
00712     int len;
00713     int i, j;
00714     int xx;
00715 
00716     he->tag = RPMTAG_PREFIXES;
00717     xx = headerGet(origH, he, 0);
00718     validType = he->t;
00719     validRelocations = he->p.argv;
00720     numValid = he->c;
00721     if (!xx)
00722         numValid = 0;
00723 
00724 assert(p != NULL);
00725     numRelocations = 0;
00726     if (p->relocs)
00727         while (p->relocs[numRelocations].newPath ||
00728                p->relocs[numRelocations].oldPath)
00729             numRelocations++;
00730 
00731     /*
00732      * If no relocations are specified (usually the case), then return the
00733      * original header. If there are prefixes, however, then INSTPREFIXES
00734      * should be added, but, since relocateFileList() can be called more
00735      * than once for the same header, don't bother if already present.
00736      */
00737     if (p->relocs == NULL || numRelocations == 0) {
00738         if (numValid) {
00739             if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES)) {
00740                 he->tag = RPMTAG_INSTPREFIXES;
00741                 he->t = validType;
00742                 he->p.argv = validRelocations;
00743                 he->c = numValid;
00744                 xx = headerPut(origH, he, 0);
00745             }
00746             validRelocations = _free(validRelocations);
00747         }
00748         /* XXX FIXME multilib file actions need to be checked. */
00749         return headerLink(origH);
00750     }
00751 
00752     h = headerLink(origH);
00753 
00754     relocations = alloca(sizeof(*relocations) * numRelocations);
00755 
00756     /* Build sorted relocation list from raw relocations. */
00757     for (i = 0; i < numRelocations; i++) {
00758         char * t;
00759 
00760         /*
00761          * Default relocations (oldPath == NULL) are handled in the UI,
00762          * not rpmlib.
00763          */
00764         if (p->relocs[i].oldPath == NULL) continue; /* XXX can't happen */
00765 
00766         /* FIXME: Trailing /'s will confuse us greatly. Internal ones will 
00767            too, but those are more trouble to fix up. :-( */
00768         t = alloca_strdup(p->relocs[i].oldPath);
00769         relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
00770             ? t
00771             : stripTrailingChar(t, '/');
00772 
00773         /* An old path w/o a new path is valid, and indicates exclusion */
00774         if (p->relocs[i].newPath) {
00775             int del;
00776 
00777             t = alloca_strdup(p->relocs[i].newPath);
00778             relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
00779                 ? t
00780                 : stripTrailingChar(t, '/');
00781 
00782             /*@-nullpass@*/     /* FIX:  relocations[i].oldPath == NULL */
00783             /* Verify that the relocation's old path is in the header. */
00784             for (j = 0; j < numValid; j++) {
00785                 if (!strcmp(validRelocations[j], relocations[i].oldPath))
00786                     /*@innerbreak@*/ break;
00787             }
00788 
00789             /* XXX actions check prevents problem from being appended twice. */
00790             if (j == numValid && !allowBadRelocate && actions) {
00791                 rpmps ps = rpmtsProblems(ts);
00792                 rpmpsAppend(ps, RPMPROB_BADRELOCATE,
00793                         rpmteNEVR(p), rpmteKey(p),
00794                         relocations[i].oldPath, NULL, NULL, 0);
00795                 ps = rpmpsFree(ps);
00796             }
00797             del =
00798                 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
00799             /*@=nullpass@*/
00800 
00801             if (del > reldel)
00802                 reldel = del;
00803         } else {
00804             relocations[i].newPath = NULL;
00805         }
00806     }
00807 
00808     /* stupid bubble sort, but it's probably faster here */
00809     for (i = 0; i < numRelocations; i++) {
00810         int madeSwap;
00811         madeSwap = 0;
00812         for (j = 1; j < numRelocations; j++) {
00813             struct rpmRelocation_s tmpReloc;
00814             if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
00815                 relocations[j    ].oldPath == NULL || /* XXX can't happen */
00816         strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
00817                 /*@innercontinue@*/ continue;
00818             /*@-usereleased@*/ /* LCL: ??? */
00819             tmpReloc = relocations[j - 1];
00820             relocations[j - 1] = relocations[j];
00821             relocations[j] = tmpReloc;
00822             /*@=usereleased@*/
00823             madeSwap = 1;
00824         }
00825         if (!madeSwap) break;
00826     }
00827 
00828     if (!_printed) {
00829         _printed = 1;
00830         rpmlog(RPMLOG_DEBUG, D_("========== relocations\n"));
00831         for (i = 0; i < numRelocations; i++) {
00832             if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
00833             if (relocations[i].newPath == NULL)
00834                 rpmlog(RPMLOG_DEBUG, D_("%5d exclude  %s\n"),
00835                         i, relocations[i].oldPath);
00836             else
00837                 rpmlog(RPMLOG_DEBUG, D_("%5d relocate %s -> %s\n"),
00838                         i, relocations[i].oldPath, relocations[i].newPath);
00839         }
00840     }
00841 
00842     /* Add relocation values to the header */
00843     if (numValid) {
00844         const char ** actualRelocations;
00845         int numActual;
00846 
00847         actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
00848         numActual = 0;
00849         for (i = 0; i < numValid; i++) {
00850             for (j = 0; j < numRelocations; j++) {
00851                 if (relocations[j].oldPath == NULL || /* XXX can't happen */
00852                     strcmp(validRelocations[i], relocations[j].oldPath))
00853                     /*@innercontinue@*/ continue;
00854                 /* On install, a relocate to NULL means skip the path. */
00855                 if (relocations[j].newPath) {
00856                     actualRelocations[numActual] = relocations[j].newPath;
00857                     numActual++;
00858                 }
00859                 /*@innerbreak@*/ break;
00860             }
00861             if (j == numRelocations) {
00862                 actualRelocations[numActual] = validRelocations[i];
00863                 numActual++;
00864             }
00865         }
00866 
00867         if (numActual) {
00868             he->tag = RPMTAG_INSTPREFIXES;
00869             he->t = RPM_STRING_ARRAY_TYPE;
00870             he->p.argv = actualRelocations;
00871             he->c = numActual;
00872             xx = headerPut(h, he, 0);
00873         }
00874 
00875         actualRelocations = _free(actualRelocations);
00876         validRelocations = _free(validRelocations);
00877     }
00878 
00879     he->tag = RPMTAG_BASENAMES;
00880     xx = headerGet(h, he, 0);
00881     baseNames = he->p.argv;
00882     fileCount = he->c;
00883     he->tag = RPMTAG_DIRINDEXES;
00884     xx = headerGet(h, he, 0);
00885     dirIndexes = he->p.ui32p;
00886     he->tag = RPMTAG_DIRNAMES;
00887     xx = headerGet(h, he, 0);
00888     dirNames = he->p.argv;
00889     dirCount = he->c;
00890     he->tag = RPMTAG_FILEFLAGS;
00891     xx = headerGet(h, he, 0);
00892     fFlags = he->p.ui32p;
00893     he->tag = RPMTAG_FILECOLORS;
00894     xx = headerGet(h, he, 0);
00895     fColors = he->p.ui32p;
00896     he->tag = RPMTAG_FILEMODES;
00897     xx = headerGet(h, he, 0);
00898     fModes = he->p.ui16p;
00899 
00900     dColors = alloca(dirCount * sizeof(*dColors));
00901     memset(dColors, 0, dirCount * sizeof(*dColors));
00902 
00903     /*
00904      * For all relocations, we go through sorted file/relocation lists 
00905      * backwards so that /usr/local relocations take precedence over /usr 
00906      * ones.
00907      */
00908 
00909     /* Relocate individual paths. */
00910 
00911     for (i = fileCount - 1; i >= 0; i--) {
00912         rpmFileTypes ft;
00913         int fnlen;
00914 
00915         len = reldel +
00916                 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
00917         if (len >= fileAlloced) {
00918             fileAlloced = len * 2;
00919             fn = xrealloc(fn, fileAlloced);
00920         }
00921 
00922 assert(fn != NULL);             /* XXX can't happen */
00923         *fn = '\0';
00924         fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
00925 
00926 if (fColors != NULL) {
00927 /* XXX pkgs may not have unique dirNames, so color all dirNames that match. */
00928 for (j = 0; j < dirCount; j++) {
00929 if (strcmp(dirNames[dirIndexes[i]], dirNames[j])) /*@innercontinue@*/ continue;
00930 dColors[j] |= fColors[i];
00931 }
00932 }
00933 
00934         /*
00935          * See if this file path needs relocating.
00936          */
00937         /*
00938          * XXX FIXME: Would a bsearch of the (already sorted) 
00939          * relocation list be a good idea?
00940          */
00941         for (j = numRelocations - 1; j >= 0; j--) {
00942             if (relocations[j].oldPath == NULL) /* XXX can't happen */
00943                 /*@innercontinue@*/ continue;
00944             len = strcmp(relocations[j].oldPath, "/")
00945                 ? strlen(relocations[j].oldPath)
00946                 : 0;
00947 
00948             if (fnlen < len)
00949                 /*@innercontinue@*/ continue;
00950             /*
00951              * Only subdirectories or complete file paths may be relocated. We
00952              * don't check for '\0' as our directory names all end in '/'.
00953              */
00954             if (!(fn[len] == '/' || fnlen == len))
00955                 /*@innercontinue@*/ continue;
00956 
00957             if (strncmp(relocations[j].oldPath, fn, len))
00958                 /*@innercontinue@*/ continue;
00959             /*@innerbreak@*/ break;
00960         }
00961         if (j < 0) continue;
00962 
00963 /*@-nullderef@*/ /* FIX: fModes may be NULL */
00964         ft = rpmfiWhatis(fModes[i]);
00965 /*@=nullderef@*/
00966 
00967         /* On install, a relocate to NULL means skip the path. */
00968         if (relocations[j].newPath == NULL) {
00969             if (ft == XDIR) {
00970                 /* Start with the parent, looking for directory to exclude. */
00971                 for (j = dirIndexes[i]; j < dirCount; j++) {
00972                     len = strlen(dirNames[j]) - 1;
00973                     while (len > 0 && dirNames[j][len-1] == '/') len--;
00974                     if (fnlen != len)
00975                         /*@innercontinue@*/ continue;
00976                     if (strncmp(fn, dirNames[j], fnlen))
00977                         /*@innercontinue@*/ continue;
00978                     /*@innerbreak@*/ break;
00979                 }
00980             }
00981             if (actions) {
00982                 actions[i] = FA_SKIPNSTATE;
00983                 rpmlog(RPMLOG_DEBUG, D_("excluding %s %s\n"),
00984                         rpmfiFtstring(ft), fn);
00985             }
00986             continue;
00987         }
00988 
00989         /* Relocation on full paths only, please. */
00990         if (fnlen != len) continue;
00991 
00992         if (actions)
00993             rpmlog(RPMLOG_DEBUG, D_("relocating %s to %s\n"),
00994                     fn, relocations[j].newPath);
00995         nrelocated++;
00996 
00997         strcpy(fn, relocations[j].newPath);
00998         {   char * te = strrchr(fn, '/');
00999             if (te) {
01000                 if (te > fn) te++;      /* root is special */
01001                 fnlen = te - fn;
01002             } else
01003                 te = fn + strlen(fn);
01004             /*@-nullpass -nullderef@*/  /* LCL: te != NULL here. */
01005             if (strcmp(baseNames[i], te)) /* basename changed too? */
01006                 baseNames[i] = alloca_strdup(te);
01007             *te = '\0';                 /* terminate new directory name */
01008             /*@=nullpass =nullderef@*/
01009         }
01010 
01011         /* Does this directory already exist in the directory list? */
01012         for (j = 0; j < dirCount; j++) {
01013             if (fnlen != strlen(dirNames[j]))
01014                 /*@innercontinue@*/ continue;
01015             if (strncmp(fn, dirNames[j], fnlen))
01016                 /*@innercontinue@*/ continue;
01017             /*@innerbreak@*/ break;
01018         }
01019         
01020         if (j < dirCount) {
01021             dirIndexes[i] = j;
01022             continue;
01023         }
01024 
01025         /* Creating new paths is a pita */
01026         if (!haveRelocatedFile) {
01027             const char ** newDirList;
01028 
01029             haveRelocatedFile = 1;
01030             newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
01031             for (j = 0; j < dirCount; j++)
01032                 newDirList[j] = alloca_strdup(dirNames[j]);
01033             dirNames = _free(dirNames);
01034             dirNames = newDirList;
01035         } else {
01036             dirNames = xrealloc(dirNames, 
01037                                sizeof(*dirNames) * (dirCount + 1));
01038         }
01039 
01040         dirNames[dirCount] = alloca_strdup(fn);
01041         dirIndexes[i] = dirCount;
01042         dirCount++;
01043     }
01044 
01045     /* Finish off by relocating directories. */
01046     for (i = dirCount - 1; i >= 0; i--) {
01047         for (j = numRelocations - 1; j >= 0; j--) {
01048 
01049            /* XXX Don't autorelocate uncolored directories. */
01050            if (j == p->autorelocatex
01051             && (dColors[i] == 0 || !(dColors[i] & mydColor)))
01052                /*@innercontinue@*/ continue;
01053 
01054             if (relocations[j].oldPath == NULL) /* XXX can't happen */
01055                 /*@innercontinue@*/ continue;
01056             len = strcmp(relocations[j].oldPath, "/")
01057                 ? strlen(relocations[j].oldPath)
01058                 : 0;
01059 
01060             if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
01061                 /*@innercontinue@*/ continue;
01062 
01063             /*
01064              * Only subdirectories or complete file paths may be relocated. We
01065              * don't check for '\0' as our directory names all end in '/'.
01066              */
01067             if (dirNames[i][len] != '/')
01068                 /*@innercontinue@*/ continue;
01069 
01070             if (relocations[j].newPath) { /* Relocate the path */
01071                 const char * s = relocations[j].newPath;
01072                 char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
01073                 size_t slen;
01074 
01075                 (void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
01076 
01077                 /* Unfortunatly rpmCleanPath strips the trailing slash.. */
01078                 (void) rpmCleanPath(t);
01079                 slen = strlen(t);
01080                 t[slen] = '/';
01081                 t[slen+1] = '\0';
01082 
01083                 if (actions)
01084                     rpmlog(RPMLOG_DEBUG,
01085                         D_("relocating directory %s to %s\n"), dirNames[i], t);
01086                 dirNames[i] = t;
01087                 nrelocated++;
01088             }
01089         }
01090     }
01091 
01092     /* Save original filenames in header and replace (relocated) filenames. */
01093     if (nrelocated) {
01094         he->tag = RPMTAG_BASENAMES;
01095         xx = headerGet(h, he, 0);
01096         he->tag = RPMTAG_ORIGBASENAMES;
01097         xx = headerPut(h, he, 0);
01098         he->p.ptr = _free(he->p.ptr);
01099 
01100         he->tag = RPMTAG_DIRNAMES;
01101         xx = headerGet(h, he, 0);
01102         he->tag = RPMTAG_ORIGDIRNAMES;
01103         xx = headerPut(h, he, 0);
01104         he->p.ptr = _free(he->p.ptr);
01105 
01106         he->tag = RPMTAG_DIRINDEXES;
01107         xx = headerGet(h, he, 0);
01108         he->tag = RPMTAG_ORIGDIRINDEXES;
01109         xx = headerPut(h, he, 0);
01110         he->p.ptr = _free(he->p.ptr);
01111 
01112         he->tag = RPMTAG_BASENAMES;
01113         he->t = RPM_STRING_ARRAY_TYPE;
01114         he->p.argv = baseNames;
01115         he->c = fileCount;
01116         xx = headerMod(h, he, 0);
01117         fi->bnl = _free(fi->bnl);
01118         xx = headerGet(h, he, 0);
01119         fi->bnl = he->p.argv;
01120         fi->fc = he->c;
01121 
01122         he->tag = RPMTAG_DIRNAMES;
01123         he->t = RPM_STRING_ARRAY_TYPE;
01124         he->p.argv = dirNames;
01125         he->c = dirCount;
01126         xx = headerMod(h, he, 0);
01127         fi->dnl = _free(fi->dnl);
01128         xx = headerGet(h, he, 0);
01129         fi->dnl = he->p.argv;
01130         fi->dc = he->c;
01131 
01132         he->tag = RPMTAG_DIRINDEXES;
01133         he->t = RPM_UINT32_TYPE;
01134         he->p.ui32p = dirIndexes;
01135         he->c = fileCount;
01136         xx = headerMod(h, he, 0);
01137         fi->dil = _free(fi->dil);
01138         xx = headerGet(h, he, 0);
01139         fi->dil = he->p.ui32p;
01140     }
01141 
01142     baseNames = _free(baseNames);
01143     dirIndexes = _free(dirIndexes);
01144     dirNames = _free(dirNames);
01145     fFlags = _free(fFlags);
01146     fColors = _free(fColors);
01147     fModes = _free(fModes);
01148 
01149 /*@-dependenttrans@*/
01150     fn = _free(fn);
01151 /*@=dependenttrans@*/
01152 
01153     return h;
01154 }
01155 
01156 rpmfi rpmfiFree(rpmfi fi)
01157 {
01158     if (fi == NULL) return NULL;
01159 
01160     if (fi->nrefs > 1)
01161         return rpmfiUnlink(fi, fi->Type);
01162 
01163 /*@-modfilesys@*/
01164 if (_rpmfi_debug < 0)
01165 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, fi->Type, fi->fc);
01166 /*@=modfilesys@*/
01167 
01168     /* Free pre- and post-transaction script and interpreter strings. */
01169     fi->pretrans = _free(fi->pretrans);
01170     fi->pretransprog = _free(fi->pretransprog);
01171     fi->posttrans = _free(fi->posttrans);
01172     fi->posttransprog = _free(fi->posttransprog);
01173     fi->verifyscript = _free(fi->verifyscript);
01174     fi->verifyscriptprog = _free(fi->verifyscriptprog);
01175 
01176     if (fi->fc > 0) {
01177         fi->bnl = _free(fi->bnl);
01178         fi->dnl = _free(fi->dnl);
01179 
01180         fi->flinks = _free(fi->flinks);
01181         fi->flangs = _free(fi->flangs);
01182         fi->fdigests = _free(fi->fdigests);
01183         fi->digests = _free(fi->digests);
01184 
01185         fi->cdict = _free(fi->cdict);
01186 
01187         fi->fuser = _free(fi->fuser);
01188         fi->fgroup = _free(fi->fgroup);
01189 
01190         fi->fstates = _free(fi->fstates);
01191 
01192         fi->fmtimes = _free(fi->fmtimes);
01193         fi->fmodes = _free(fi->fmodes);
01194         fi->fflags = _free(fi->fflags);
01195         fi->vflags = _free(fi->vflags);
01196         fi->fsizes = _free(fi->fsizes);
01197         fi->frdevs = _free(fi->frdevs);
01198         fi->finodes = _free(fi->finodes);
01199         fi->dil = _free(fi->dil);
01200 
01201         fi->fcolors = _free(fi->fcolors);
01202         fi->fcdictx = _free(fi->fcdictx);
01203         fi->ddict = _free(fi->ddict);
01204         fi->fddictx = _free(fi->fddictx);
01205         fi->fddictn = _free(fi->fddictn);
01206     }
01207 
01208     fi->fsm = freeFSM(fi->fsm);
01209 
01210     fi->fn = _free(fi->fn);
01211     fi->apath = _free(fi->apath);
01212     fi->fmapflags = _free(fi->fmapflags);
01213 
01214     fi->obnl = _free(fi->obnl);
01215     fi->odnl = _free(fi->odnl);
01216 
01217     fi->fcontexts = _free(fi->fcontexts);
01218 
01219     fi->actions = _free(fi->actions);
01220     fi->replacedSizes = _free(fi->replacedSizes);
01221 
01222     fi->h = headerFree(fi->h);
01223 
01224     /*@-nullstate -refcounttrans -usereleased@*/
01225     (void) rpmfiUnlink(fi, fi->Type);
01226     memset(fi, 0, sizeof(*fi));         /* XXX trash and burn */
01227     fi = _free(fi);
01228     /*@=nullstate =refcounttrans =usereleased@*/
01229 
01230     return NULL;
01231 }
01232 
01238 static inline unsigned char nibble(char c)
01239         /*@*/
01240 {
01241     if (c >= '0' && c <= '9')
01242         return (c - '0');
01243     if (c >= 'A' && c <= 'F')
01244         return (c - 'A') + 10;
01245     if (c >= 'a' && c <= 'f')
01246         return (c - 'a') + 10;
01247     return 0;
01248 }
01249 
01250 #define _fdupestring(_h, _tag, _data) \
01251     he->tag = _tag; \
01252     xx = headerGet((_h), he, 0); \
01253     _data = he->p.str;
01254 
01255 #define _fdupedata(_h, _tag, _data) \
01256     he->tag = _tag; \
01257     xx = headerGet((_h), he, 0); \
01258     _data = he->p.ptr;
01259 
01260 rpmfi rpmfiNew(const rpmts ts, Header h, rpmTag tagN, int flags)
01261 {
01262     int scareMem = (flags & 0x1);
01263     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01264     rpmte p;
01265     rpmfi fi = NULL;
01266     const char * Type;
01267     int dnlmax, bnlmax;
01268     unsigned char * t;
01269     int len;
01270     int xx;
01271     int i;
01272 
01273 assert(scareMem == 0);          /* XXX always allocate memory */
01274     if (tagN == RPMTAG_BASENAMES) {
01275         Type = "Files";
01276     } else {
01277         Type = "?Type?";
01278         goto exit;
01279     }
01280 
01281     fi = xcalloc(1, sizeof(*fi));
01282     if (fi == NULL)     /* XXX can't happen */
01283         goto exit;
01284 
01285     fi->magic = RPMFIMAGIC;
01286     fi->Type = Type;
01287     fi->i = -1;
01288     fi->tagN = tagN;
01289 
01290     fi->h = NULL;
01291     fi->isSource =
01292         (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
01293          headerIsEntry(h, RPMTAG_ARCH) != 0);
01294 
01295     if (fi->fsm == NULL)
01296         fi->fsm = newFSM();
01297 
01298     fi->fsm->repackaged = (headerIsEntry(h, RPMTAG_REMOVETID) ? 1 : 0);
01299 
01300     /* 0 means unknown */
01301     he->tag = RPMTAG_ARCHIVESIZE;
01302     xx = headerGet(h, he, 0);
01303     fi->archivePos = 0;
01304     fi->archiveSize = (xx && he->p.ui32p ? he->p.ui32p[0] : 0);
01305     he->p.ptr = _free(he->p.ptr);
01306 
01307     /* Extract pre- and post-transaction script and interpreter strings. */
01308     _fdupestring(h, RPMTAG_PRETRANS, fi->pretrans);
01309     _fdupestring(h, RPMTAG_PRETRANSPROG, fi->pretransprog);
01310     _fdupestring(h, RPMTAG_POSTTRANS, fi->posttrans);
01311     _fdupestring(h, RPMTAG_POSTTRANSPROG, fi->posttransprog);
01312     _fdupestring(h, RPMTAG_VERIFYSCRIPT, fi->verifyscript);
01313     _fdupestring(h, RPMTAG_VERIFYSCRIPTPROG, fi->verifyscriptprog);
01314 
01315     he->tag = RPMTAG_BASENAMES;
01316     xx = headerGet(h, he, 0);
01317     fi->bnl = he->p.argv;
01318     fi->fc = he->c;
01319     if (!xx) {
01320         fi->fc = 0;
01321         fi->dc = 0;
01322         goto exit;
01323     }
01324     _fdupedata(h, RPMTAG_DIRNAMES, fi->dnl);
01325     fi->dc = he->c;
01326     _fdupedata(h, RPMTAG_DIRINDEXES, fi->dil);
01327     _fdupedata(h, RPMTAG_FILEMODES, fi->fmodes);
01328     _fdupedata(h, RPMTAG_FILEFLAGS, fi->fflags);
01329     _fdupedata(h, RPMTAG_FILEVERIFYFLAGS, fi->vflags);
01330     _fdupedata(h, RPMTAG_FILESIZES, fi->fsizes);
01331 
01332     _fdupedata(h, RPMTAG_FILECOLORS, fi->fcolors);
01333     fi->color = 0;
01334     if (fi->fcolors != NULL)
01335     for (i = 0; i < fi->fc; i++)
01336         fi->color |= fi->fcolors[i];
01337     _fdupedata(h, RPMTAG_CLASSDICT, fi->cdict);
01338     fi->ncdict = he->c;
01339     _fdupedata(h, RPMTAG_FILECLASS, fi->fcdictx);
01340 
01341     _fdupedata(h, RPMTAG_DEPENDSDICT, fi->ddict);
01342     fi->nddict = he->c;
01343     _fdupedata(h, RPMTAG_FILEDEPENDSX, fi->fddictx);
01344     _fdupedata(h, RPMTAG_FILEDEPENDSN, fi->fddictn);
01345 
01346     _fdupedata(h, RPMTAG_FILESTATES, fi->fstates);
01347     if (xx == 0 || fi->fstates == NULL)
01348         fi->fstates = xcalloc(fi->fc, sizeof(*fi->fstates));
01349 
01350     fi->action = FA_UNKNOWN;
01351     fi->flags = 0;
01352 
01353 if (fi->actions == NULL)
01354         fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
01355 
01356     /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
01357     fi->mapflags =
01358                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01359 
01360     _fdupedata(h, RPMTAG_FILELINKTOS, fi->flinks);
01361     _fdupedata(h, RPMTAG_FILELANGS, fi->flangs);
01362 
01363     fi->digestalgo = PGPHASHALGO_MD5;
01364     fi->digestlen = 16;
01365     fi->fdigestalgos = NULL;
01366     _fdupedata(h, RPMTAG_FILEDIGESTALGOS, fi->fdigestalgos);
01367     if (fi->fdigestalgos) {
01368         int dalgo = 0;
01369         /* XXX Insure that all algorithms are either 0 or constant. */
01370         for (i = 0; i < fi->fc; i++) {
01371             if (fi->fdigestalgos[i] == 0)
01372                 continue;
01373             if (dalgo == 0)
01374                 dalgo = fi->fdigestalgos[i];
01375             else
01376 assert(dalgo == fi->fdigestalgos[i]);
01377         }
01378         fi->digestalgo = dalgo;
01379         switch (dalgo) {
01380         case PGPHASHALGO_MD5:           fi->digestlen = 128/8;  break;
01381         case PGPHASHALGO_SHA1:          fi->digestlen = 160/8;  break;
01382         case PGPHASHALGO_RIPEMD128:     fi->digestlen = 128/8;  break;
01383         case PGPHASHALGO_RIPEMD160:     fi->digestlen = 160/8;  break;
01384         case PGPHASHALGO_SHA256:        fi->digestlen = 256/8;  break;
01385         case PGPHASHALGO_SHA384:        fi->digestlen = 384/8;  break;
01386         case PGPHASHALGO_SHA512:        fi->digestlen = 512/8;  break;
01387         case PGPHASHALGO_CRC32:         fi->digestlen = 32/8;   break;
01388         }
01389         fi->fdigestalgos = _free(fi->fdigestalgos);
01390     }
01391 
01392     _fdupedata(h, RPMTAG_FILEDIGESTS, fi->fdigests);
01393     fi->digests = NULL;
01394     if (fi->fdigests) {
01395         t = xmalloc(fi->fc * fi->digestlen);
01396         fi->digests = t;
01397         for (i = 0; i < fi->fc; i++) {
01398             const char * fdigests;
01399             int j;
01400 
01401             fdigests = fi->fdigests[i];
01402             if (!(fdigests && *fdigests != '\0')) {
01403                 memset(t, 0, fi->digestlen);
01404                 t += fi->digestlen;
01405                 continue;
01406             }
01407             for (j = 0; j < fi->digestlen; j++, t++, fdigests += 2)
01408                 *t = (nibble(fdigests[0]) << 4) | nibble(fdigests[1]);
01409         }
01410         fi->fdigests = _free(fi->fdigests);
01411     }
01412 
01413     /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes, or fcontexts */
01414     _fdupedata(h, RPMTAG_FILEMTIMES, fi->fmtimes);
01415     _fdupedata(h, RPMTAG_FILERDEVS, fi->frdevs);
01416     _fdupedata(h, RPMTAG_FILEINODES, fi->finodes);
01417     _fdupedata(h, RPMTAG_FILECONTEXTS, fi->fcontexts);
01418 
01419     fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
01420 
01421     _fdupedata(h, RPMTAG_FILEUSERNAME, fi->fuser);
01422     _fdupedata(h, RPMTAG_FILEGROUPNAME, fi->fgroup);
01423 
01424     if (ts != NULL)
01425     if (fi != NULL)
01426     if ((p = rpmtsRelocateElement(ts)) != NULL && rpmteType(p) == TR_ADDED
01427      && headerIsEntry(h, RPMTAG_SOURCERPM)
01428      && !headerIsEntry(h, RPMTAG_ORIGBASENAMES))
01429     {
01430         const char * fmt = rpmGetPath("%{?_autorelocate_path}", NULL);
01431         const char * errstr;
01432         char * newPath;
01433         Header foo;
01434 
01435         /* XXX error handling. */
01436         newPath = headerSprintf(h, fmt, NULL, rpmHeaderFormats, &errstr);
01437         fmt = _free(fmt);
01438 
01439         /* XXX Make sure autoreloc is not already specified. */
01440         i = p->nrelocs;
01441         if (newPath != NULL && *newPath != '\0' && p->relocs != NULL)
01442         for (i = 0; i < p->nrelocs; i++) {
01443 /*@-nullpass@*/ /* XXX {old,new}Path might be NULL */
01444            if (strcmp(p->relocs[i].oldPath, "/"))
01445                 continue;
01446            if (strcmp(p->relocs[i].newPath, newPath))
01447                 continue;
01448 /*@=nullpass@*/
01449            break;
01450         }
01451 
01452         /* XXX test for incompatible arch triggering autorelocation is dumb. */
01453         /* XXX DIEDIEDIE: used to test '... && p->archScore == 0' */
01454         if (newPath != NULL && *newPath != '\0' && i == p->nrelocs) {
01455 
01456             p->relocs =
01457                 xrealloc(p->relocs, (p->nrelocs + 2) * sizeof(*p->relocs));
01458             p->relocs[p->nrelocs].oldPath = xstrdup("/");
01459             p->relocs[p->nrelocs].newPath = xstrdup(newPath);
01460             p->autorelocatex = p->nrelocs;
01461             p->nrelocs++;
01462             p->relocs[p->nrelocs].oldPath = NULL;
01463             p->relocs[p->nrelocs].newPath = NULL;
01464         }
01465         newPath = _free(newPath);
01466 
01467 /* XXX DYING */
01468 if (fi->actions == NULL)
01469         fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
01470         /*@-compdef@*/ /* FIX: fi->digests undefined */
01471         foo = relocateFileList(ts, fi, h, fi->actions);
01472         /*@=compdef@*/
01473         fi->h = headerFree(fi->h);
01474         fi->h = headerLink(foo);
01475         foo = headerFree(foo);
01476     }
01477 
01478     if (fi->isSource && fi->dc == 1 && *fi->dnl[0] == '\0') {
01479         const char ** av = xcalloc(4+1, sizeof(*av));
01480         char * te;
01481         size_t nb;
01482 
01483         xx = headerMacrosLoad(h);
01484         av[0] = rpmGenPath(rpmtsRootDir(ts), "%{_sourcedir}", "");
01485         av[1] = rpmGenPath(rpmtsRootDir(ts), "%{_specdir}", "");
01486         av[2] = rpmGenPath(rpmtsRootDir(ts), "%{_patchdir}", "");
01487         av[3] = rpmGenPath(rpmtsRootDir(ts), "%{_icondir}", "");
01488         av[4] = NULL;
01489         xx = headerMacrosUnload(h);
01490 
01491         /* Hack up a header RPM_STRING_ARRAY_TYPE array. */
01492         fi->dnl = _free(fi->dnl);
01493         fi->dc = 4;
01494         nb = fi->dc * sizeof(*av);
01495         for (i = 0; i < fi->dc; i++)
01496             nb += strlen(av[i]) + sizeof("/");
01497 
01498         fi->dnl = xmalloc(nb);
01499         te = (char *) (&fi->dnl[fi->dc]);
01500         *te = '\0';
01501         for (i = 0; i < fi->dc; i++) {
01502             fi->dnl[i] = te;
01503             te = stpcpy( stpcpy(te, av[i]), "/");
01504             *te++ = '\0';
01505         }
01506         av = argvFree(av);
01507 
01508         /* Map basenames to appropriate directories. */
01509         for (i = 0; i < fi->fc; i++) {
01510             if (fi->fflags[i] & RPMFILE_SOURCE)
01511                 fi->dil[i] = 0;
01512             else if (fi->fflags[i] & RPMFILE_SPECFILE)
01513                 fi->dil[i] = 1;
01514             else if (fi->fflags[i] & RPMFILE_PATCH)
01515                 fi->dil[i] = 2;
01516             else if (fi->fflags[i] & RPMFILE_ICON)
01517                 fi->dil[i] = 3;
01518             else {
01519                 const char * b = fi->bnl[i];
01520                 const char * be = b + strlen(b) - sizeof(".spec") - 1;
01521 
01522                 fi->dil[i] = (be > b && !strcmp(be, ".spec") ? 1 : 0);
01523             }
01524         }
01525     }
01526 
01527     if (!scareMem)
01528         fi->h = headerFree(fi->h);
01529 
01530     dnlmax = -1;
01531     for (i = 0; i < fi->dc; i++) {
01532         if ((len = strlen(fi->dnl[i])) > dnlmax)
01533             dnlmax = len;
01534     }
01535     bnlmax = -1;
01536     for (i = 0; i < fi->fc; i++) {
01537         if ((len = strlen(fi->bnl[i])) > bnlmax)
01538             bnlmax = len;
01539     }
01540     fi->fnlen = dnlmax + bnlmax + 1;
01541     fi->fn = NULL;
01542 
01543     fi->dperms = 0755;
01544     fi->fperms = 0644;
01545 
01546 exit:
01547 /*@-modfilesys@*/
01548 if (_rpmfi_debug < 0)
01549 fprintf(stderr, "*** fi %p\t%s[%d]\n", fi, Type, (fi ? fi->fc : 0));
01550 /*@=modfilesys@*/
01551 
01552     /*@-compdef -nullstate@*/ /* FIX: rpmfi null annotations */
01553     return rpmfiLink(fi, (fi ? fi->Type : NULL));
01554     /*@=compdef =nullstate@*/
01555 }
01556 
01557 void rpmfiBuildFClasses(Header h,
01558         /*@out@*/ const char *** fclassp, /*@out@*/ uint32_t * fcp)
01559 {
01560     int scareMem = 0;
01561     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, scareMem);
01562     const char * FClass;
01563     const char ** av;
01564     int ac;
01565     size_t nb;
01566     char * t;
01567 
01568     if ((ac = rpmfiFC(fi)) <= 0) {
01569         av = NULL;
01570         ac = 0;
01571         goto exit;
01572     }
01573 
01574     /* Compute size of file class argv array blob. */
01575     nb = (ac + 1) * sizeof(*av);
01576     fi = rpmfiInit(fi, 0);
01577     if (fi != NULL)
01578     while (rpmfiNext(fi) >= 0) {
01579         FClass = rpmfiFClass(fi);
01580         if (FClass && *FClass != '\0')
01581             nb += strlen(FClass);
01582         nb += 1;
01583     }
01584 
01585     /* Create and load file class argv array. */
01586     av = xmalloc(nb);
01587     t = ((char *) av) + ((ac + 1) * sizeof(*av));
01588     ac = 0;
01589     fi = rpmfiInit(fi, 0);
01590     if (fi != NULL)
01591     while (rpmfiNext(fi) >= 0) {
01592         FClass = rpmfiFClass(fi);
01593         av[ac++] = t;
01594         if (FClass && *FClass != '\0')
01595             t = stpcpy(t, FClass);
01596         *t++ = '\0';
01597     }
01598     av[ac] = NULL;      /* XXX tag arrays are not NULL terminated. */
01599 
01600 exit:
01601     fi = rpmfiFree(fi);
01602     if (fclassp)
01603         *fclassp = av;
01604     else
01605         av = _free(av);
01606     if (fcp) *fcp = ac;
01607 }
01608 
01609 void rpmfiBuildFContexts(Header h,
01610         /*@out@*/ const char *** fcontextp, /*@out@*/ uint32_t * fcp)
01611 {
01612     int scareMem = 0;
01613     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, scareMem);
01614     const char * fcontext;
01615     const char ** av;
01616     int ac;
01617     size_t nb;
01618     char * t;
01619 
01620     if ((ac = rpmfiFC(fi)) <= 0) {
01621         av = NULL;
01622         ac = 0;
01623         goto exit;
01624     }
01625 
01626     /* Compute size of argv array blob. */
01627     nb = (ac + 1) * sizeof(*av);
01628     fi = rpmfiInit(fi, 0);
01629     if (fi != NULL)
01630     while (rpmfiNext(fi) >= 0) {
01631         fcontext = rpmfiFContext(fi);
01632         if (fcontext && *fcontext != '\0')
01633             nb += strlen(fcontext);
01634         nb += 1;
01635     }
01636 
01637     /* Create and load argv array. */
01638     av = xmalloc(nb);
01639     t = ((char *) av) + ((ac + 1) * sizeof(*av));
01640     ac = 0;
01641     fi = rpmfiInit(fi, 0);
01642     if (fi != NULL)
01643     while (rpmfiNext(fi) >= 0) {
01644         fcontext = rpmfiFContext(fi);
01645         av[ac++] = t;
01646         if (fcontext && *fcontext != '\0')
01647             t = stpcpy(t, fcontext);
01648         *t++ = '\0';
01649     }
01650     av[ac] = NULL;      /* XXX tag arrays are not NULL terminated. */
01651 
01652 exit:
01653     fi = rpmfiFree(fi);
01654     if (fcontextp)
01655         *fcontextp = av;
01656     else
01657         av = _free(av);
01658     if (fcp) *fcp = ac;
01659 }
01660 
01661 void rpmfiBuildFSContexts(Header h,
01662         /*@out@*/ const char *** fcontextp, /*@out@*/ uint32_t * fcp)
01663 {
01664     int scareMem = 0;
01665     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, scareMem);
01666     const char ** av;
01667     int ac;
01668     size_t nb;
01669     char * t;
01670     char * fctxt = NULL;
01671     size_t fctxtlen = 0;
01672     int * fcnb;
01673 
01674     if ((ac = rpmfiFC(fi)) <= 0) {
01675         av = NULL;
01676         ac = 0;
01677         goto exit;
01678     }
01679 
01680     /* Compute size of argv array blob, concatenating file contexts. */
01681     nb = ac * sizeof(*fcnb);
01682     fcnb = memset(alloca(nb), 0, nb);
01683     ac = 0;
01684     fi = rpmfiInit(fi, 0);
01685     if (fi != NULL)
01686     while (rpmfiNext(fi) >= 0) {
01687         const char *fn;
01688         security_context_t scon;
01689 
01690         fn = rpmfiFN(fi);
01691         fcnb[ac] = lgetfilecon(fn, &scon);
01692         if (fcnb[ac] > 0) {
01693             fctxt = xrealloc(fctxt, fctxtlen + fcnb[ac]);
01694             memcpy(fctxt+fctxtlen, scon, fcnb[ac]);
01695             fctxtlen += fcnb[ac];
01696             freecon(scon);
01697         }
01698         ac++;
01699     }
01700 
01701     /* Create and load argv array from concatenated file contexts. */
01702     nb = (ac + 1) * sizeof(*av) + fctxtlen;
01703     av = xmalloc(nb);
01704     t = ((char *) av) + ((ac + 1) * sizeof(*av));
01705     if (fctxt != NULL && fctxtlen > 0)
01706         (void) memcpy(t, fctxt, fctxtlen);
01707     ac = 0;
01708     fi = rpmfiInit(fi, 0);
01709     if (fi != NULL)
01710     while (rpmfiNext(fi) >= 0) {
01711         av[ac] = "";
01712         if (fcnb[ac] > 0) {
01713             av[ac] = t;
01714             t += fcnb[ac];
01715         }
01716         ac++;
01717     }
01718     av[ac] = NULL;      /* XXX tag arrays are not NULL terminated. */
01719 
01720 exit:
01721     fi = rpmfiFree(fi);
01722     if (fcontextp)
01723         *fcontextp = av;
01724     else
01725         av = _free(av);
01726     if (fcp) *fcp = ac;
01727 }
01728 
01729 void rpmfiBuildREContexts(Header h,
01730         /*@out@*/ const char *** fcontextp, /*@out@*/ uint32_t * fcp)
01731 {
01732     int scareMem = 0;
01733     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, scareMem);
01734     const char ** av = NULL;
01735     int ac;
01736     size_t nb;
01737     char * t;
01738     char * fctxt = NULL;
01739     size_t fctxtlen = 0;
01740     int * fcnb;
01741 
01742     if ((ac = rpmfiFC(fi)) <= 0) {
01743         ac = 0;
01744         goto exit;
01745     }
01746 
01747     /* Read security context patterns. */
01748     {   const char *fn = rpmGetPath("%{?__file_context_path}", NULL);
01749 /*@-moduncon -noeffectuncon @*/
01750         if (fn != NULL && *fn != '\0')
01751             (void)matchpathcon_init(fn);
01752 /*@=moduncon =noeffectuncon @*/
01753         fn = _free(fn);
01754     }
01755 
01756     /* Compute size of argv array blob, concatenating file contexts. */
01757     nb = ac * sizeof(*fcnb);
01758     fcnb = memset(alloca(nb), 0, nb);
01759     ac = 0;
01760     fi = rpmfiInit(fi, 0);
01761     if (fi != NULL)
01762     while (rpmfiNext(fi) >= 0) {
01763         const char *fn;
01764         mode_t fmode;
01765         security_context_t scon;
01766 
01767         fn = rpmfiFN(fi);
01768         fmode = rpmfiFMode(fi);
01769         scon = NULL;
01770 /*@-moduncon@*/
01771         if (matchpathcon(fn, fmode, &scon) == 0 && scon != NULL) {
01772             fcnb[ac] = strlen(scon) + 1;
01773             if (fcnb[ac] > 0) {
01774                 fctxt = xrealloc(fctxt, fctxtlen + fcnb[ac]);
01775                 memcpy(fctxt+fctxtlen, scon, fcnb[ac]);
01776                 fctxtlen += fcnb[ac];
01777             }
01778             freecon(scon);
01779         }
01780 /*@=moduncon@*/
01781         ac++;
01782     }
01783 
01784     /* Create and load argv array from concatenated file contexts. */
01785     nb = (ac + 1) * sizeof(*av) + fctxtlen;
01786     av = xmalloc(nb);
01787     t = ((char *) av) + ((ac + 1) * sizeof(*av));
01788     (void) memcpy(t, fctxt, fctxtlen);
01789     ac = 0;
01790     fi = rpmfiInit(fi, 0);
01791     if (fi != NULL)
01792     while (rpmfiNext(fi) >= 0) {
01793         av[ac] = "";
01794         if (fcnb[ac] > 0) {
01795             av[ac] = t;
01796             t += fcnb[ac];
01797         }
01798         ac++;
01799     }
01800     av[ac] = NULL;      /* XXX tag arrays are not NULL terminated. */
01801 
01802 exit:
01803 /*@-moduncon -noeffectuncon @*/
01804     matchpathcon_fini();
01805 /*@=moduncon =noeffectuncon @*/
01806     fi = rpmfiFree(fi);
01807     if (fcontextp)
01808         *fcontextp = av;
01809     else
01810         av = _free(av);
01811     if (fcp) *fcp = ac;
01812 }
01813 
01814 void rpmfiBuildFDeps(Header h, rpmTag tagN,
01815         /*@out@*/ const char *** fdepsp, /*@out@*/ uint32_t * fcp)
01816 {
01817     int scareMem = 0;
01818     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, scareMem);
01819     rpmds ds = NULL;
01820     const char ** av;
01821     int ac;
01822     size_t nb;
01823     char * t;
01824     char deptype = 'R';
01825     char mydt;
01826     const char * DNEVR;
01827     const uint32_t * ddict;
01828     unsigned ix;
01829     int ndx;
01830 
01831     if ((ac = rpmfiFC(fi)) <= 0) {
01832         av = NULL;
01833         ac = 0;
01834         goto exit;
01835     }
01836 
01837     if (tagN == RPMTAG_PROVIDENAME)
01838         deptype = 'P';
01839     else if (tagN == RPMTAG_REQUIRENAME)
01840         deptype = 'R';
01841 
01842     ds = rpmdsNew(h, tagN, scareMem);
01843 
01844     /* Compute size of file depends argv array blob. */
01845     nb = (ac + 1) * sizeof(*av);
01846     fi = rpmfiInit(fi, 0);
01847     if (fi != NULL)
01848     while (rpmfiNext(fi) >= 0) {
01849         ddict = NULL;
01850         ndx = rpmfiFDepends(fi, &ddict);
01851         if (ddict != NULL)
01852         while (ndx-- > 0) {
01853             ix = *ddict++;
01854             mydt = ((ix >> 24) & 0xff);
01855             if (mydt != deptype)
01856                 /*@innercontinue@*/ continue;
01857             ix &= 0x00ffffff;
01858             (void) rpmdsSetIx(ds, ix-1);
01859             if (rpmdsNext(ds) < 0)
01860                 /*@innercontinue@*/ continue;
01861             DNEVR = rpmdsDNEVR(ds);
01862             if (DNEVR != NULL)
01863                 nb += strlen(DNEVR+2) + 1;
01864         }
01865         nb += 1;
01866     }
01867 
01868     /* Create and load file depends argv array. */
01869     av = xmalloc(nb);
01870     t = ((char *) av) + ((ac + 1) * sizeof(*av));
01871     ac = 0;
01872     fi = rpmfiInit(fi, 0);
01873     if (fi != NULL)
01874     while (rpmfiNext(fi) >= 0) {
01875         av[ac++] = t;
01876         ddict = NULL;
01877         ndx = rpmfiFDepends(fi, &ddict);
01878         if (ddict != NULL)
01879         while (ndx-- > 0) {
01880             ix = *ddict++;
01881             mydt = ((ix >> 24) & 0xff);
01882             if (mydt != deptype)
01883                 /*@innercontinue@*/ continue;
01884             ix &= 0x00ffffff;
01885             (void) rpmdsSetIx(ds, ix-1);
01886             if (rpmdsNext(ds) < 0)
01887                 /*@innercontinue@*/ continue;
01888             DNEVR = rpmdsDNEVR(ds);
01889             if (DNEVR != NULL) {
01890                 t = stpcpy(t, DNEVR+2);
01891                 *t++ = ' ';
01892                 *t = '\0';
01893             }
01894         }
01895         *t++ = '\0';
01896     }
01897     av[ac] = NULL;      /* XXX tag arrays are not NULL terminated. */
01898 
01899 exit:
01900     fi = rpmfiFree(fi);
01901     ds = rpmdsFree(ds);
01902     if (fdepsp)
01903         *fdepsp = av;
01904     else
01905         av = _free(av);
01906     if (fcp) *fcp = ac;
01907 }

Generated on Mon Nov 29 2010 05:18:44 for rpm by  doxygen 1.7.2