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