rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

lib/rpmfi.c
Go to the documentation of this file.

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