rpm 5.3.7

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