rpm 5.2.1

lib/rpmfi.c

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