- 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 }