rpm  5.2.1
lib/fsm.c
Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio_internal.h>     /* XXX urlPath, fdGetCpioPos */
00009 #include <rpmcb.h>              /* XXX fnpyKey */
00010 #include <rpmtag.h>
00011 #include <rpmtypes.h>
00012 
00013 #define _RPMFI_INTERNAL
00014 #include "rpmfi.h"
00015 
00016 #define _IOSM_INTERNAL
00017 #include <fsm.h>
00018 #define fsmUNSAFE       fsmStage
00019 
00020 #if defined(SUPPORT_AR_PAYLOADS)
00021 #include "ar.h"
00022 #endif
00023 #include "cpio.h"
00024 #include "tar.h"
00025 
00026 #define _USE_RPMTE
00027 #if defined(_USE_RPMTE)
00028 #include "rpmte.h"
00029 #endif
00030 #include "rpmts.h"
00031 #include "rpmsq.h"
00032 
00033 #include "ugid.h"               /* XXX unameToUid() and gnameToGid() */
00034 
00035 #include "debug.h"
00036 
00037 /*@access FD_t @*/      /* XXX void ptr args */
00038 /*@access FSMI_t @*/
00039 /*@access IOSM_t @*/
00040 /*@access IOSMI_t @*/
00041 
00042 /*@access rpmfi @*/
00043 
00044 /*@access rpmsx @*/     /* XXX cast */
00045 /*@access rpmte @*/     /* XXX cast */
00046 /*@access rpmts @*/     /* XXX cast */
00047 
00048 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00049 
00050 #define _FSM_DEBUG      0
00051 /*@unchecked@*/
00052 int _fsm_debug = _FSM_DEBUG;
00053 
00054 /*@-exportheadervar@*/
00055 /*@unchecked@*/
00056 int _fsm_threads = 0;
00057 /*@=exportheadervar@*/
00058 
00064 static rpmts fsmGetTs(const IOSM_t fsm)
00065         /*@*/
00066 {
00067     const FSMI_t iter = fsm->iter;
00068     /*@-compdef -refcounttrans -retexpose -usereleased @*/
00069     return (iter ? iter->ts : NULL);
00070     /*@=compdef =refcounttrans =retexpose =usereleased @*/
00071 }
00072 
00078 static rpmfi fsmGetFi(const IOSM_t fsm)
00079         /*@*/
00080 {
00081     const FSMI_t iter = fsm->iter;
00082     /*@-compdef -refcounttrans -retexpose -usereleased @*/
00083     return (iter ? iter->fi : NULL);
00084     /*@=compdef =refcounttrans =retexpose =usereleased @*/
00085 }
00086 
00087 #define SUFFIX_RPMORIG  ".rpmorig"
00088 #define SUFFIX_RPMSAVE  ".rpmsave"
00089 #define SUFFIX_RPMNEW   ".rpmnew"
00090 
00099 static /*@only@*//*@null@*/
00100 const char * fsmFsPath(/*@special@*/ /*@null@*/ const IOSM_t fsm,
00101                 /*@null@*/ const struct stat * st,
00102                 /*@null@*/ const char * subdir,
00103                 /*@null@*/ const char * suffix)
00104         /*@uses fsm->dirName, fsm->baseName */
00105         /*@*/
00106 {
00107     const char * s = NULL;
00108 
00109     if (fsm) {
00110         char * t;
00111         int nb;
00112         nb = strlen(fsm->dirName) +
00113             (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) +
00114             (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) +
00115             strlen(fsm->baseName) + 1;
00116         s = t = xmalloc(nb);
00117         t = stpcpy(t, fsm->dirName);
00118         if (st && !S_ISDIR(st->st_mode))
00119             if (subdir) t = stpcpy(t, subdir);
00120         t = stpcpy(t, fsm->baseName);
00121         if (st && !S_ISDIR(st->st_mode))
00122             if (suffix) t = stpcpy(t, suffix);
00123     }
00124     return s;
00125 }
00126 
00132 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p)
00133         /*@globals fileSystem @*/
00134         /*@modifies fileSystem @*/
00135 {
00136     FSMI_t iter = p;
00137     if (iter) {
00138         iter->fi = rpmfiUnlink(iter->fi, "mapIterator");
00139 /*@-internalglobs@*/ /* XXX rpmswExit() */
00140         (void)rpmtsFree(iter->ts); 
00141         iter->ts = NULL;
00142 /*@=internalglobs@*/
00143     }
00144     return _free(p);
00145 }
00146 
00153 static void *
00154 mapInitIterator(rpmfi fi, int reverse)
00155         /*@modifies fi @*/
00156 {
00157     FSMI_t iter = NULL;
00158 
00159     iter = xcalloc(1, sizeof(*iter));
00160 /*@-assignexpose -castexpose @*/
00161     iter->fi = rpmfiLink(fi, "mapIterator");
00162 /*@=assignexpose =castexpose @*/
00163     iter->reverse = reverse;
00164     iter->i = (iter->reverse ? (fi->fc - 1) : 0);
00165     iter->isave = iter->i;
00166     return iter;
00167 }
00168 
00174 static int mapNextIterator(/*@null@*/ void * a)
00175         /*@*/
00176 {
00177     FSMI_t iter = a;
00178     int i = -1;
00179 
00180     if (iter) {
00181 /*@-onlytrans@*/
00182         const rpmfi fi = iter->fi;
00183 /*@=onlytrans@*/
00184         if (iter->reverse) {
00185             if (iter->i >= 0)   i = iter->i--;
00186         } else {
00187             if (iter->i < (int)fi->fc)  i = iter->i++;
00188         }
00189         iter->isave = i;
00190     }
00191     return i;
00192 }
00193 
00196 static int cpioStrCmp(const void * a, const void * b)
00197         /*@*/
00198 {
00199     const char * aurl = *(const char **)a;
00200     const char * burl = *(const char **)b;
00201     const char * afn = NULL;
00202     const char * bfn = NULL;
00203 
00204     (void) urlPath(aurl, &afn);
00205     (void) urlPath(burl, &bfn);
00206 
00207 #ifdef  VERY_OLD_BUGGY_RPM_PACKAGES
00208     /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */
00209     if (strchr(afn, '/') == NULL)
00210         bfn = strrchr(bfn, '/') + 1;
00211 #endif
00212 
00213     /* Match rpm-4.0 payloads with ./ prefixes. */
00214     if (afn[0] == '.' && afn[1] == '/') afn += 2;
00215     if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
00216 
00217     /* If either path is absolute, make it relative to '/'. */
00218     if (afn[0] == '/')  afn += 1;
00219     if (bfn[0] == '/')  bfn += 1;
00220 
00221     return strcmp(afn, bfn);
00222 }
00223 
00230 static int mapFind(/*@null@*/ FSMI_t iter, const char * fsmPath)
00231         /*@modifies iter @*/
00232 {
00233     int ix = -1;
00234 
00235     if (iter) {
00236 /*@-onlytrans@*/
00237         const rpmfi fi = iter->fi;
00238 /*@=onlytrans@*/
00239         size_t fc = rpmfiFC(fi);
00240         if (fi && fc > 0 && fi->apath && fsmPath && *fsmPath) {
00241             const char ** p = NULL;
00242 
00243             if (fi->apath != NULL)
00244                 p = bsearch(&fsmPath, fi->apath, fc, sizeof(fsmPath),
00245                         cpioStrCmp);
00246             if (p) {
00247                 iter->i = p - fi->apath;
00248                 ix = mapNextIterator(iter);
00249             }
00250         }
00251     }
00252     return ix;
00253 }
00254 
00258 typedef struct dnli_s {
00259     rpmfi fi;
00260 /*@only@*/ /*@null@*/
00261     char * active;
00262     int reverse;
00263     int isave;
00264     int i;
00265 } * DNLI_t;
00266 
00272 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a)
00273         /*@modifies a @*/
00274 {
00275     if (a) {
00276         DNLI_t dnli = (void *)a;
00277         if (dnli->active) free(dnli->active);
00278     }
00279     return _free(a);
00280 }
00281 
00284 static inline int dnlCount(/*@null@*/ const DNLI_t dnli)
00285         /*@*/
00286 {
00287     return (int) (dnli ? dnli->fi->dc : 0);
00288 }
00289 
00292 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli)
00293         /*@*/
00294 {
00295     return (dnli ? dnli->isave : -1);
00296 }
00297 
00304 /*@-usereleased@*/
00305 static /*@only@*/ /*@null@*/
00306 void * dnlInitIterator(/*@special@*/ const IOSM_t fsm,
00307                 int reverse)
00308         /*@uses fsm->iter @*/ 
00309         /*@*/
00310 {
00311     rpmfi fi = fsmGetFi(fsm);
00312     const char * dnl;
00313     DNLI_t dnli;
00314     int i, j;
00315 
00316     if (fi == NULL)
00317         return NULL;
00318     dnli = xcalloc(1, sizeof(*dnli));
00319     dnli->fi = fi;
00320     dnli->reverse = reverse;
00321     dnli->i = (int) (reverse ? fi->dc : 0);
00322 
00323     if (fi->dc) {
00324         dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
00325 
00326         /* Identify parent directories not skipped. */
00327         if ((fi = rpmfiInit(fi, 0)) != NULL)
00328         while ((i = rpmfiNext(fi)) >= 0) {
00329             if (!iosmFileActionSkipped(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
00330         }
00331 
00332         /* Exclude parent directories that are explicitly included. */
00333         if ((fi = rpmfiInit(fi, 0)) != NULL)
00334         while ((i = rpmfiNext(fi)) >= 0) {
00335             rpmuint32_t dil;
00336             size_t dnlen, bnlen;
00337 
00338             if (!S_ISDIR(fi->fmodes[i]))
00339                 continue;
00340 
00341             dil = fi->dil[i];
00342             dnlen = strlen(fi->dnl[dil]);
00343             bnlen = strlen(fi->bnl[i]);
00344 
00345             for (j = 0; j < (int)fi->dc; j++) {
00346                 size_t jlen;
00347 
00348                 if (!dnli->active[j] || j == (int)dil)
00349                     /*@innercontinue@*/ continue;
00350                 (void) urlPath(fi->dnl[j], &dnl);
00351                 jlen = strlen(dnl);
00352                 if (jlen != (dnlen+bnlen+1))
00353                     /*@innercontinue@*/ continue;
00354                 if (strncmp(dnl, fi->dnl[dil], dnlen))
00355                     /*@innercontinue@*/ continue;
00356                 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen))
00357                     /*@innercontinue@*/ continue;
00358                 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
00359                     /*@innercontinue@*/ continue;
00360                 /* This directory is included in the package. */
00361                 dnli->active[j] = 0;
00362                 /*@innerbreak@*/ break;
00363             }
00364         }
00365 
00366         /* Print only once per package. */
00367         if (!reverse) {
00368             j = 0;
00369             for (i = 0; i < (int)fi->dc; i++) {
00370                 if (!dnli->active[i]) continue;
00371                 if (j == 0) {
00372                     j = 1;
00373                     rpmlog(RPMLOG_DEBUG,
00374         D_("========== Directories not explicitly included in package:\n"));
00375                 }
00376                 (void) urlPath(fi->dnl[i], &dnl);
00377                 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl);
00378             }
00379             if (j)
00380                 rpmlog(RPMLOG_DEBUG, "==========\n");
00381         }
00382     }
00383     return dnli;
00384 }
00385 /*@=usereleased@*/
00386 
00392 static /*@observer@*/ /*@null@*/
00393 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli)
00394         /*@modifies dnli @*/
00395 {
00396     const char * dn = NULL;
00397 
00398     if (dnli) {
00399         rpmfi fi = dnli->fi;
00400         int i = -1;
00401 
00402         if (dnli->active)
00403         do {
00404             i = (!dnli->reverse ? dnli->i++ : --dnli->i);
00405         } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]);
00406 
00407         if (i >= 0 && i < (int)fi->dc)
00408             dn = fi->dnl[i];
00409         else
00410             i = -1;
00411         dnli->isave = i;
00412     }
00413     return dn;
00414 }
00415 
00416 #if defined(WITH_PTHREADS)
00417 static void * fsmThread(void * arg)
00418         /*@globals h_errno, fileSystem, internalState @*/
00419         /*@modifies arg, fileSystem, internalState @*/
00420 {
00421     IOSM_t fsm = arg;
00422 /*@-unqualifiedtrans@*/
00423     return ((void *) ((long)fsmStage(fsm, fsm->nstage)));
00424 /*@=unqualifiedtrans@*/
00425 }
00426 #endif
00427 
00428 int fsmNext(IOSM_t fsm, iosmFileStage nstage)
00429         /*@globals h_errno, fileSystem, internalState @*/
00430         /*@modifies fsm, fileSystem, internalState @*/
00431 {
00432     fsm->nstage = nstage;
00433 #if defined(WITH_PTHREADS)
00434     if (fsm->multithreaded)
00435         return rpmsqJoin( rpmsqThread(fsmThread, fsm) );
00436 #endif
00437     return fsmStage(fsm, fsm->nstage);
00438 }
00439 
00445 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t fsm)
00446         /*@uses fsm->links, fsm->ix, fsm->sb, fsm->goal, fsm->nsuffix @*/
00447         /*@defines fsm->li @*/
00448         /*@releases fsm->path @*/
00449         /*@globals h_errno, fileSystem, internalState @*/
00450         /*@modifies fsm, fileSystem, internalState @*/
00451 {
00452     struct stat * st = &fsm->sb;
00453     int rc = 0;
00454     int ix = -1;
00455     int j;
00456 
00457     /* Find hard link set. */
00458     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
00459         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
00460             break;
00461     }
00462 
00463     /* New hard link encountered, add new link to set. */
00464     if (fsm->li == NULL) {
00465         fsm->li = xcalloc(1, sizeof(*fsm->li));
00466         fsm->li->next = NULL;
00467         fsm->li->sb = *st;      /* structure assignment */
00468         fsm->li->nlink = (int) st->st_nlink;
00469         fsm->li->linkIndex = fsm->ix;
00470         fsm->li->createdPath = -1;
00471 
00472         fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
00473         memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
00474         fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
00475 
00476         if (fsm->goal == IOSM_PKGBUILD)
00477             fsm->li->linksLeft = (int) st->st_nlink;
00478         if (fsm->goal == IOSM_PKGINSTALL)
00479             fsm->li->linksLeft = 0;
00480 
00481         /*@-kepttrans@*/
00482         fsm->li->next = fsm->links;
00483         /*@=kepttrans@*/
00484         fsm->links = fsm->li;
00485     }
00486 
00487     if (fsm->goal == IOSM_PKGBUILD) --fsm->li->linksLeft;
00488     fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
00489     /*@-observertrans -dependenttrans@*/
00490     fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
00491     /*@=observertrans =dependenttrans@*/
00492     if (fsm->goal == IOSM_PKGINSTALL) fsm->li->linksLeft++;
00493 
00494     if (fsm->goal == IOSM_PKGBUILD)
00495         return (fsm->li->linksLeft > 0);
00496 
00497     if (fsm->goal != IOSM_PKGINSTALL)
00498         return 0;
00499 
00500     if (!(st->st_size || fsm->li->linksLeft == (int) st->st_nlink))
00501         return 1;
00502 
00503     /* Here come the bits, time to choose a non-skipped file name. */
00504     {   rpmfi fi = fsmGetFi(fsm);
00505 
00506         for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
00507             ix = fsm->li->filex[j];
00508             if (ix < 0 || iosmFileActionSkipped(fi->actions[ix]))
00509                 continue;
00510             break;
00511         }
00512     }
00513 
00514     /* Are all links skipped or not encountered yet? */
00515     if (ix < 0 || j < 0)
00516         return 1;       /* XXX W2DO? */
00517 
00518     /* Save the non-skipped file name and map index. */
00519     fsm->li->linkIndex = j;
00520     fsm->path = _free(fsm->path);
00521     fsm->ix = ix;
00522     rc = fsmNext(fsm, IOSM_MAP);
00523     return rc;
00524 }
00525 
00531 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li)
00532         /*@modifies li @*/
00533 {
00534     if (li) {
00535         li->nsuffix = _free(li->nsuffix);       /* XXX elements are shared */
00536         li->filex = _free(li->filex);
00537     }
00538     return _free(li);
00539 }
00540 
00541 IOSM_t newFSM(void)
00542 {
00543     IOSM_t fsm = xcalloc(1, sizeof(*fsm));
00544     return fsm;
00545 }
00546 
00547 IOSM_t freeFSM(IOSM_t fsm)
00548 {
00549     if (fsm) {
00550         fsm->path = _free(fsm->path);
00551         while ((fsm->li = fsm->links) != NULL) {
00552             fsm->links = fsm->li->next;
00553             fsm->li->next = NULL;
00554             fsm->li = freeHardLink(fsm->li);
00555         }
00556         fsm->dnlx = _free(fsm->dnlx);
00557         fsm->ldn = _free(fsm->ldn);
00558         fsm->iter = mapFreeIterator(fsm->iter);
00559     }
00560     return _free(fsm);
00561 }
00562 
00563 #if defined(SUPPORT_AR_PAYLOADS)
00564 static int arSetup(IOSM_t fsm, rpmfi fi)
00565         /*@modifies fsm @*/
00566 {
00567     const char * path;
00568     char * t;
00569     size_t lmtablen = 0;
00570     size_t nb;
00571 
00572     /* Calculate size of ar(1) long member table. */
00573     if ((fi = rpmfiInit(fi, 0)) != NULL)
00574     while (rpmfiNext(fi) >= 0) {
00575 #ifdef  NOTYET
00576         if (fi->apath) {
00577             const char * apath = NULL;
00578             (void) urlPath(fi->apath[ix], &apath);
00579             path = apath + fi->striplen;
00580         } else
00581 #endif
00582             path = rpmfiBN(fi);
00583         if ((nb = strlen(path)) < 15)
00584             continue;
00585         lmtablen += nb + 1;     /* trailing \n */
00586     }
00587 
00588     /* Anything to do? */
00589     if (lmtablen == 0)
00590         return 0;
00591 
00592     /* Create and load ar(1) long member table. */
00593     fsm->lmtab = t = xmalloc(lmtablen + 1);     /* trailing \0 */
00594     fsm->lmtablen = lmtablen;
00595     fsm->lmtaboff = 0;
00596     if ((fi = rpmfiInit(fi, 0)) != NULL)
00597     while (rpmfiNext(fi) >= 0) {
00598 #ifdef  NOTYET
00599         if (fi->apath) {
00600             const char * apath = NULL;
00601             (void) urlPath(fi->apath[ix], &apath);
00602             path = apath + fi->striplen;
00603         } else
00604 #endif
00605             path = rpmfiBN(fi);
00606         if ((nb = strlen(path)) < 15)
00607             continue;
00608         t = stpcpy(t, path);
00609         *t++ = '\n';
00610     }
00611     *t = '\0';
00612     
00613     return 0;
00614 }
00615 #endif
00616 
00617 int fsmSetup(void * _fsm, iosmFileStage goal, const char * afmt,
00618                 const void * _ts, const void * _fi, FD_t cfd,
00619                 unsigned int * archiveSize, const char ** failedFile)
00620 {
00621     IOSM_t fsm = _fsm;
00622 /*@-castexpose@*/
00623     const rpmts ts = (const rpmts) _ts;
00624     const rpmfi fi = (const rpmfi) _fi;
00625 /*@=castexpose@*/
00626 #if defined(_USE_RPMTE)
00627     int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT);
00628     int adding = (rpmteType(fi->te) == TR_ADDED);
00629 #else
00630     int reverse = 0;    /* XXX HACK: devise alternative means */
00631     int adding = 1;     /* XXX HACK: devise alternative means */
00632 #endif
00633     size_t pos = 0;
00634     int rc, ec = 0;
00635 
00636     fsm->debug = _fsm_debug;
00637     fsm->multithreaded = _fsm_threads;
00638     fsm->adding = adding;
00639 
00640 /*@+voidabstract -nullpass@*/
00641 if (fsm->debug < 0)
00642 fprintf(stderr, "--> fsmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", fsm, goal, afmt, (void *)ts, fi, cfd, archiveSize, failedFile);
00643 /*@=voidabstract =nullpass@*/
00644 
00645     _iosmNext = &fsmNext;
00646     if (fsm->headerRead == NULL) {
00647         if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) {
00648 if (fsm->debug < 0)
00649 fprintf(stderr, "\ttar vectors set\n");
00650             fsm->headerRead = &tarHeaderRead;
00651             fsm->headerWrite = &tarHeaderWrite;
00652             fsm->trailerWrite = &tarTrailerWrite;
00653             fsm->blksize = TAR_BLOCK_SIZE;
00654         } else
00655 #if defined(SUPPORT_AR_PAYLOADS)
00656         if (afmt != NULL && !strcmp(afmt, "ar")) {
00657 if (fsm->debug < 0)
00658 fprintf(stderr, "\tar vectors set\n");
00659             fsm->headerRead = &arHeaderRead;
00660             fsm->headerWrite = &arHeaderWrite;
00661             fsm->trailerWrite = &arTrailerWrite;
00662             fsm->blksize = 2;
00663             if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE)
00664                 (void) arSetup(fsm, fi);
00665         } else
00666 #endif
00667         {
00668 if (fsm->debug < 0)
00669 fprintf(stderr, "\tcpio vectors set\n");
00670             fsm->headerRead = &cpioHeaderRead;
00671             fsm->headerWrite = &cpioHeaderWrite;
00672             fsm->trailerWrite = &cpioTrailerWrite;
00673             fsm->blksize = 4;
00674         }
00675     }
00676 
00677     fsm->goal = goal;
00678     if (cfd != NULL) {
00679 /*@-assignexpose -castexpose @*/
00680         fsm->cfd = fdLink(cfd, "persist (fsm)");
00681 /*@=assignexpose =castexpose @*/
00682         pos = fdGetCpioPos(fsm->cfd);
00683         fdSetCpioPos(fsm->cfd, 0);
00684     }
00685 /*@-mods@*/     /* LCL: avoid void * _ts/_fi annotations for now. */
00686     fsm->iter = mapInitIterator(fi, reverse);
00687 /*@-assignexpose -castexpose @*/
00688     fsm->iter->ts = rpmtsLink(ts, "mapIterator");
00689 /*@=assignexpose =castexpose @*/
00690     fsm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS);
00691 /*@=mods@*/
00692     fsm->nofdigests =
00693         (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS))
00694                         ? 0 : 1;
00695 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
00696     fsm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) &&
00697                         fsm->goal != IOSM_PKGCOMMIT) ? 0 : 1);
00698 #undef _tsmask
00699 
00700     if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
00701         void * ptr;
00702         fi->archivePos = 0;
00703         ptr = rpmtsNotify(ts, fi->te,
00704                 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize);
00705     }
00706 
00707     /*@-assignexpose@*/
00708     fsm->archiveSize = archiveSize;
00709     if (fsm->archiveSize)
00710         *fsm->archiveSize = 0;
00711     fsm->failedFile = failedFile;
00712     if (fsm->failedFile)
00713         *fsm->failedFile = NULL;
00714     /*@=assignexpose@*/
00715 
00716     memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf));
00717     if (fsm->goal == IOSM_PKGINSTALL) {
00718         if (ts && rpmtsGetTid(ts) != (rpmuint32_t)-1)
00719             sprintf(fsm->sufbuf, ";%08x", (unsigned)rpmtsGetTid(ts));
00720     }
00721 
00722     ec = fsm->rc = 0;
00723 /*@-mods@*/     /* LCL: avoid void * _fsm annotation for now. */
00724     rc = fsmUNSAFE(fsm, IOSM_CREATE);
00725 /*@=mods@*/
00726     if (rc && !ec) ec = rc;
00727 
00728 /*@-mods@*/     /* LCL: avoid void * _fsm annotation for now. */
00729     rc = fsmUNSAFE(fsm, fsm->goal);
00730 /*@=mods@*/
00731     if (rc && !ec) ec = rc;
00732 
00733     if (fsm->archiveSize && ec == 0)
00734         *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos);
00735 
00736 /*@-nullstate@*/ /* FIX: *fsm->failedFile may be NULL */
00737    return ec;
00738 /*@=nullstate@*/
00739 }
00740 
00741 int fsmTeardown(void * _fsm)
00742 {
00743     IOSM_t fsm = _fsm;
00744     int rc = fsm->rc;
00745 
00746 if (fsm->debug < 0)
00747 fprintf(stderr, "--> fsmTeardown(%p)\n", fsm);
00748     if (!rc)
00749         rc = fsmUNSAFE(fsm, IOSM_DESTROY);
00750 
00751         (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
00752                         &fsm->op_digest);
00753 
00754     fsm->lmtab = _free(fsm->lmtab);
00755     (void)rpmtsFree(fsm->iter->ts); 
00756     fsm->iter->ts = NULL;
00757     fsm->iter = mapFreeIterator(fsm->iter);
00758     if (fsm->cfd != NULL) {
00759 /*@-refcounttrans@*/    /* FIX: XfdFree annotation */
00760         fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
00761 /*@=refcounttrans@*/
00762         fsm->cfd = NULL;
00763     }
00764     fsm->failedFile = NULL;
00765     return rc;
00766 }
00767 
00768 /*
00769  * Set file security context (if not disabled).
00770  * @param fsm           file state machine data
00771  * @return              0 always
00772  */
00773 static int fsmMapFContext(IOSM_t fsm)
00774         /*@modifies fsm @*/
00775 {
00776     fsm->fcontext = NULL;
00777     if (!fsm->nofcontexts) {
00778         security_context_t scon = NULL;
00779 /*@-moduncon@*/
00780         int xx = matchpathcon(fsm->path, fsm->sb.st_mode, &scon);
00781 /*@=moduncon@*/
00782 
00783         if (!xx && scon != NULL)
00784             fsm->fcontext = scon;
00785 #ifdef  DYING   /* XXX SELinux file contexts not set from package content. */
00786         else {
00787             rpmfi fi = fsmGetFi(fsm);
00788             int i = fsm->ix;
00789 
00790             /* Get file security context from package. */
00791             if (fi && i >= 0 && i < (int)fi->fc)
00792                 fsm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL);
00793         }
00794 #endif
00795     }
00796     return 0;
00797 }
00798 
00799 int fsmMapPath(IOSM_t fsm)
00800 {
00801     rpmfi fi = fsmGetFi(fsm);   /* XXX const except for fstates */
00802     int teAdding = fsm->adding;
00803     int rc = 0;
00804     int i = fsm->ix;
00805 
00806     fsm->osuffix = NULL;
00807     fsm->nsuffix = NULL;
00808     fsm->astriplen = 0;
00809     fsm->action = FA_UNKNOWN;
00810     fsm->mapFlags = fi->mapflags;
00811 
00812     if (fi && i >= 0 && i < (int)fi->fc) {
00813 
00814         fsm->astriplen = fi->astriplen;
00815         fsm->action = (fi->actions ? fi->actions[i] : fi->action);
00816         fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
00817         fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
00818 
00819         /* src rpms have simple base name in payload. */
00820         fsm->dirName = fi->dnl[fi->dil[i]];
00821         fsm->baseName = fi->bnl[i];
00822 
00823         switch (fsm->action) {
00824         case FA_SKIP:
00825             break;
00826         case FA_UNKNOWN:
00827             break;
00828 
00829         case FA_COPYOUT:
00830             break;
00831         case FA_COPYIN:
00832         case FA_CREATE:
00833 assert(teAdding);
00834             break;
00835 
00836         case FA_SKIPNSTATE:
00837             if (fi->fstates && teAdding)
00838                 fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
00839             break;
00840 
00841         case FA_SKIPNETSHARED:
00842             if (fi->fstates && teAdding)
00843                 fi->fstates[i] = RPMFILE_STATE_NETSHARED;
00844             break;
00845 
00846         case FA_SKIPCOLOR:
00847             if (fi->fstates && teAdding)
00848                 fi->fstates[i] = RPMFILE_STATE_WRONGCOLOR;
00849             break;
00850 
00851         case FA_BACKUP:
00852             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00853                 fsm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE);
00854             break;
00855 
00856         case FA_ALTNAME:
00857 assert(teAdding);
00858             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00859                 fsm->nsuffix = SUFFIX_RPMNEW;
00860             break;
00861 
00862         case FA_SAVE:
00863 assert(teAdding);
00864             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00865                 fsm->osuffix = SUFFIX_RPMSAVE;
00866             break;
00867         case FA_ERASE:
00868 #if 0   /* XXX is this a genhdlist fix? */
00869             assert(rpmteType(fi->te) == TR_REMOVED);
00870 #endif
00871             /*
00872              * XXX TODO: %ghost probably shouldn't be removed, but that changes
00873              * legacy rpm behavior.
00874              */
00875             break;
00876         default:
00877             break;
00878         }
00879 
00880         if ((fsm->mapFlags & IOSM_MAP_PATH) || fsm->nsuffix) {
00881             const struct stat * st = &fsm->sb;
00882             fsm->path = _free(fsm->path);
00883             fsm->path = fsmFsPath(fsm, st, fsm->subdir,
00884                 (fsm->suffix ? fsm->suffix : fsm->nsuffix));
00885         }
00886     }
00887     return rc;
00888 }
00889 
00890 int fsmMapAttrs(IOSM_t fsm)
00891 {
00892     struct stat * st = &fsm->sb;
00893     rpmfi fi = fsmGetFi(fsm);
00894     int i = fsm->ix;
00895 
00896     if (fi && i >= 0 && i < (int) fi->fc) {
00897         mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
00898         mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms);
00899         dev_t finalRdev = (dev_t)(fi->frdevs ? fi->frdevs[i] : 0);
00900         rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
00901         uid_t uid = fi->uid;
00902         gid_t gid = fi->gid;
00903 
00904 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00905         /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during
00906            installation of _source_ RPMs. Instead, let it use the current
00907            run-time owner/group, because most of the time the owner/group in
00908            the source RPM (which is the owner/group of the files as staying on
00909            the package author system) is not existing on the target system, of
00910            course. */
00911 #endif
00912         if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
00913 #if defined(RPM_VENDOR_OPENPKG) ||defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00914           if (!fi->isSource) {
00915 #endif
00916             if (fsm->goal == IOSM_PKGINSTALL)
00917                 rpmlog(RPMLOG_WARNING,
00918                     _("user %s does not exist - using root\n"), fi->fuser[i]);
00919             uid = 0;
00920             finalMode &= ~S_ISUID;      /* turn off suid bit */
00921 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00922           }
00923 #endif
00924         }
00925 
00926         if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
00927 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00928           if (!fi->isSource) {
00929 #endif
00930             if (fsm->goal == IOSM_PKGINSTALL)
00931                 rpmlog(RPMLOG_WARNING,
00932                     _("group %s does not exist - using root\n"), fi->fgroup[i]);
00933             gid = 0;
00934             finalMode &= ~S_ISGID;      /* turn off sgid bit */
00935 #if defined(RPM_VENDOR_OPENPKG) ||  defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00936           }
00937 #endif
00938         }
00939 
00940         if (fsm->mapFlags & IOSM_MAP_MODE)
00941             st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
00942         if (fsm->mapFlags & IOSM_MAP_TYPE) {
00943             st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
00944             if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00945             && st->st_nlink == 0)
00946                 st->st_nlink = 1;
00947             st->st_rdev = finalRdev;
00948             st->st_mtime = finalMtime;
00949         }
00950         if (fsm->mapFlags & IOSM_MAP_UID)
00951             st->st_uid = uid;
00952         if (fsm->mapFlags & IOSM_MAP_GID)
00953             st->st_gid = gid;
00954 
00955         /*
00956          * Set file digest (if not disabled).
00957          */
00958         if (!fsm->nofdigests) {
00959             fsm->fdigestalgo = fi->digestalgo;
00960             fsm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL);
00961             fsm->digestlen = fi->digestlen;
00962             fsm->digest = (fi->digests ? (fi->digests + (fsm->digestlen * i)) : NULL);
00963         } else {
00964             fsm->fdigestalgo = 0;
00965             fsm->fdigest = NULL;
00966             fsm->digestlen = 0;
00967             fsm->digest = NULL;
00968         }
00969     }
00970     return 0;
00971 }
00972 
00978 /*@-compdef@*/
00979 static int extractRegular(/*@special@*/ IOSM_t fsm)
00980         /*@uses fsm->fdigest, fsm->digest, fsm->sb, fsm->wfd  @*/
00981         /*@globals h_errno, fileSystem, internalState @*/
00982         /*@modifies fsm, fileSystem, internalState @*/
00983 {
00984     const struct stat * st = &fsm->sb;
00985     size_t left = (size_t) st->st_size;
00986     int rc = 0;
00987     int xx;
00988 
00989     rc = fsmNext(fsm, IOSM_WOPEN);
00990     if (rc)
00991         goto exit;
00992 
00993     if (st->st_size > 0 && (fsm->fdigest != NULL || fsm->digest != NULL))
00994         fdInitDigest(fsm->wfd, fsm->fdigestalgo, 0);
00995 
00996     while (left) {
00997 
00998         fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
00999         rc = fsmNext(fsm, IOSM_DREAD);
01000         if (rc)
01001             goto exit;
01002 
01003         rc = fsmNext(fsm, IOSM_WRITE);
01004         if (rc)
01005             goto exit;
01006 
01007         left -= fsm->wrnb;
01008 
01009         /* Notify iff progress, completion is done elsewhere */
01010         if (!rc && left)
01011             (void) fsmNext(fsm, IOSM_NOTIFY);
01012     }
01013 
01014     xx = fsync(Fileno(fsm->wfd));
01015 
01016     if (st->st_size > 0 && (fsm->fdigest || fsm->digest)) {
01017         void * digest = NULL;
01018         int asAscii = (fsm->digest == NULL ? 1 : 0);
01019 
01020         (void) Fflush(fsm->wfd);
01021         fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii);
01022 
01023         if (digest == NULL) {
01024             rc = IOSMERR_DIGEST_MISMATCH;
01025             goto exit;
01026         }
01027 
01028         if (fsm->digest != NULL) {
01029             if (memcmp(digest, fsm->digest, fsm->digestlen))
01030                 rc = IOSMERR_DIGEST_MISMATCH;
01031         } else {
01032             if (strcmp(digest, fsm->fdigest))
01033                 rc = IOSMERR_DIGEST_MISMATCH;
01034         }
01035         digest = _free(digest);
01036     }
01037 
01038 exit:
01039     (void) fsmNext(fsm, IOSM_WCLOSE);
01040     return rc;
01041 }
01042 /*@=compdef@*/
01043 
01050 /*@-compdef -compmempass@*/
01051 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t fsm, int writeData)
01052         /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/
01053         /*@globals h_errno, fileSystem, internalState @*/
01054         /*@modifies fsm, fileSystem, internalState @*/
01055 {
01056     const char * path = fsm->path;
01057     const char * opath = fsm->opath;
01058     struct stat * st = &fsm->sb;
01059     struct stat * ost = &fsm->osb;
01060     size_t left;
01061     int xx;
01062     int rc;
01063 
01064     st->st_size = (writeData ? ost->st_size : 0);
01065 
01066     if (S_ISDIR(st->st_mode)) {
01067         st->st_size = 0;
01068     } else if (S_ISLNK(st->st_mode)) {
01069         /*
01070          * While linux puts the size of a symlink in the st_size field,
01071          * I don't think that's a specified standard.
01072          */
01073         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
01074         rc = fsmUNSAFE(fsm, IOSM_READLINK);
01075         if (rc) goto exit;
01076         st->st_size = fsm->rdnb;
01077         fsm->lpath = xstrdup(fsm->rdbuf);       /* XXX save readlink return. */
01078     }
01079 
01080     if (fsm->mapFlags & IOSM_MAP_ABSOLUTE) {
01081         size_t nb= strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof(".");
01082         char * t = alloca(nb);
01083         *t = '\0';
01084         fsm->path = t;
01085         if (fsm->mapFlags & IOSM_MAP_ADDDOT)
01086             *t++ = '.';
01087         t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName);
01088     } else if (fsm->mapFlags & IOSM_MAP_PATH) {
01089         rpmfi fi = fsmGetFi(fsm);
01090         if (fi->apath) {
01091             const char * apath = NULL;
01092             (void) urlPath(fi->apath[fsm->ix], &apath);
01093             fsm->path = apath + fi->striplen;
01094         } else
01095             fsm->path = fi->bnl[fsm->ix];
01096     }
01097 
01098     rc = fsmNext(fsm, IOSM_HWRITE);
01099     fsm->path = path;
01100     if (rc) goto exit;
01101 
01102     if (writeData && S_ISREG(st->st_mode)) {
01103 #if defined(HAVE_MMAP)
01104         char * rdbuf = NULL;
01105         void * mapped = (void *)-1;
01106         size_t nmapped = 0;
01107         /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
01108         int use_mmap = (st->st_size <= 0x07ffffff);
01109 #endif
01110 
01111         rc = fsmNext(fsm, IOSM_ROPEN);
01112         if (rc) goto exit;
01113 
01114         /* XXX unbuffered mmap generates *lots* of fdio debugging */
01115 #if defined(HAVE_MMAP)
01116         if (use_mmap) {
01117             mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
01118             if (mapped != (void *)-1) {
01119                 rdbuf = fsm->rdbuf;
01120                 fsm->rdbuf = (char *) mapped;
01121                 fsm->rdlen = nmapped = st->st_size;
01122 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
01123                 xx = madvise(mapped, nmapped, MADV_DONTNEED);
01124 #endif
01125             }
01126         }
01127 #endif
01128 
01129         left = st->st_size;
01130 
01131         while (left) {
01132 #if defined(HAVE_MMAP)
01133           if (mapped != (void *)-1) {
01134             fsm->rdnb = nmapped;
01135           } else
01136 #endif
01137           {
01138             fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
01139             rc = fsmNext(fsm, IOSM_READ);
01140             if (rc) goto exit;
01141           }
01142 
01143             /* XXX DWRITE uses rdnb for I/O length. */
01144             rc = fsmNext(fsm, IOSM_DWRITE);
01145             if (rc) goto exit;
01146 
01147             left -= fsm->wrnb;
01148         }
01149 
01150 #if defined(HAVE_MMAP)
01151         if (mapped != (void *)-1) {
01152 /* XXX splint misses size_t 2nd arg. */
01153 /*@i@*/     xx = msync(mapped, nmapped, MS_ASYNC);
01154 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
01155             xx = madvise(mapped, nmapped, MADV_DONTNEED);
01156 #endif
01157             xx = munmap(mapped, nmapped);
01158             fsm->rdbuf = rdbuf;
01159         } else
01160 #endif
01161             xx = fsync(Fileno(fsm->rfd));
01162 
01163     }
01164 
01165     rc = fsmNext(fsm, IOSM_PAD);
01166     if (rc) goto exit;
01167 
01168     rc = 0;
01169 
01170 exit:
01171     if (fsm->rfd != NULL)
01172         (void) fsmNext(fsm, IOSM_RCLOSE);
01173 /*@-dependenttrans@*/
01174     fsm->opath = opath;
01175     fsm->path = path;
01176 /*@=dependenttrans@*/
01177     return rc;
01178 }
01179 /*@=compdef =compmempass@*/
01180 
01186 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t fsm)
01187         /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/
01188         /*@globals h_errno, fileSystem, internalState @*/
01189         /*@modifies fsm, fileSystem, internalState @*/
01190 {
01191     const char * path = fsm->path;
01192     const char * lpath = fsm->lpath;
01193     const char * nsuffix = fsm->nsuffix;
01194     int iterIndex = fsm->ix;
01195     int ec = 0;
01196     int rc;
01197     int i;
01198     const char * linkpath = NULL;
01199     int firstfile = 1;
01200 
01201     fsm->path = NULL;
01202     fsm->lpath = NULL;
01203     fsm->nsuffix = NULL;
01204     fsm->ix = -1;
01205 
01206     for (i = fsm->li->nlink - 1; i >= 0; i--) {
01207 
01208         if (fsm->li->filex[i] < 0) continue;
01209 
01210         fsm->ix = fsm->li->filex[i];
01211 /*@-compdef@*/
01212         rc = fsmNext(fsm, IOSM_MAP);
01213 /*@=compdef@*/
01214 
01215         /* XXX tar and cpio have to do things differently. */
01216         if (fsm->headerWrite == tarHeaderWrite) {
01217             if (firstfile) {
01218                 const char * apath = NULL;
01219                 char *t;
01220                 (void) urlPath(fsm->path, &apath);
01221                 /* Remove the buildroot prefix. */
01222                 t = xmalloc(sizeof(".") + strlen(apath + fsm->astriplen));
01223                 (void) stpcpy( stpcpy(t, "."), apath + fsm->astriplen);
01224                 linkpath = t;
01225                 firstfile = 0;
01226             } else
01227                 fsm->lpath = linkpath;
01228 
01229             /* Write data after first link for tar. */
01230             rc = writeFile(fsm, (fsm->lpath == NULL));
01231         } else {
01232             /* Write data after last link for cpio. */
01233             rc = writeFile(fsm, (i == 0));
01234         }
01235         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01236             ec = rc;
01237             *fsm->failedFile = xstrdup(fsm->path);
01238         }
01239 
01240         fsm->path = _free(fsm->path);
01241         fsm->li->filex[i] = -1;
01242     }
01243 
01244 /*@-dependenttrans@*/
01245     linkpath = _free(linkpath);
01246 /*@=dependenttrans@*/
01247     fsm->ix = iterIndex;
01248     fsm->nsuffix = nsuffix;
01249     fsm->lpath = lpath;
01250     fsm->path = path;
01251     return ec;
01252 }
01253 
01259 /*@-compdef@*/
01260 static int fsmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm)
01261         /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/
01262         /*@globals h_errno, fileSystem, internalState @*/
01263         /*@modifies fsm, fileSystem, internalState @*/
01264 {
01265     const char * path = fsm->path;
01266     const char * opath = fsm->opath;
01267     const char * nsuffix = fsm->nsuffix;
01268     int iterIndex = fsm->ix;
01269     int ec = 0;
01270     int rc;
01271     int i;
01272 
01273     fsm->path = NULL;
01274     fsm->opath = NULL;
01275     fsm->nsuffix = NULL;
01276     fsm->ix = -1;
01277 
01278     fsm->ix = fsm->li->filex[fsm->li->createdPath];
01279     rc = fsmNext(fsm, IOSM_MAP);
01280     fsm->opath = fsm->path;
01281     fsm->path = NULL;
01282     for (i = 0; i < fsm->li->nlink; i++) {
01283         if (fsm->li->filex[i] < 0) continue;
01284         if (fsm->li->createdPath == i) continue;
01285 
01286         fsm->ix = fsm->li->filex[i];
01287         fsm->path = _free(fsm->path);
01288         rc = fsmNext(fsm, IOSM_MAP);
01289         if (iosmFileActionSkipped(fsm->action)) continue;
01290 
01291         rc = fsmUNSAFE(fsm, IOSM_VERIFY);
01292         if (!rc) continue;
01293         if (!(rc == IOSMERR_ENOENT)) break;
01294 
01295         /* XXX link(fsm->opath, fsm->path) */
01296         rc = fsmNext(fsm, IOSM_LINK);
01297         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01298             ec = rc;
01299             *fsm->failedFile = xstrdup(fsm->path);
01300         }
01301 
01302         fsm->li->linksLeft--;
01303     }
01304     fsm->path = _free(fsm->path);
01305     fsm->opath = _free(fsm->opath);
01306 
01307     fsm->ix = iterIndex;
01308     fsm->nsuffix = nsuffix;
01309     fsm->path = path;
01310     fsm->opath = opath;
01311     return ec;
01312 }
01313 /*@=compdef@*/
01314 
01320 /*@-compdef@*/
01321 static int fsmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t fsm)
01322         /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb,
01323                 fsm->li, fsm->links @*/
01324         /*@globals h_errno, fileSystem, internalState @*/
01325         /*@modifies fsm, fileSystem, internalState @*/
01326 {
01327     const char * path = fsm->path;
01328     const char * nsuffix = fsm->nsuffix;
01329     int iterIndex = fsm->ix;
01330     struct stat * st = &fsm->sb;
01331     int rc = 0;
01332     int i;
01333 
01334     fsm->path = NULL;
01335     fsm->nsuffix = NULL;
01336     fsm->ix = -1;
01337 
01338     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
01339         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
01340             break;
01341     }
01342 
01343     for (i = 0; i < fsm->li->nlink; i++) {
01344         if (fsm->li->filex[i] < 0) continue;
01345         fsm->ix = fsm->li->filex[i];
01346         rc = fsmNext(fsm, IOSM_MAP);
01347         if (!iosmFileActionSkipped(fsm->action))
01348             rc = fsmNext(fsm, IOSM_COMMIT);
01349         fsm->path = _free(fsm->path);
01350         fsm->li->filex[i] = -1;
01351     }
01352 
01353     fsm->ix = iterIndex;
01354     fsm->nsuffix = nsuffix;
01355     fsm->path = path;
01356     return rc;
01357 }
01358 /*@=compdef@*/
01359 
01365 static int fsmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm)
01366         /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/
01367         /*@globals h_errno, fileSystem, internalState @*/
01368         /*@modifies fsm, fileSystem, internalState @*/
01369 {
01370     const char * path = fsm->path;
01371     void * dnli = dnlInitIterator(fsm, 1);
01372     char * dn = fsm->rdbuf;
01373     int dc = dnlCount(dnli);
01374     int rc = 0;
01375 
01376     fsm->path = NULL;
01377     dn[0] = '\0';
01378     /*@-observertrans -dependenttrans@*/
01379     if (fsm->ldn != NULL && fsm->dnlx != NULL)
01380     while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
01381         size_t dnlen = strlen(fsm->path);
01382         char * te;
01383 
01384         dc = dnlIndex(dnli);
01385         if (fsm->dnlx[dc] < 1 || (size_t)fsm->dnlx[dc] >= dnlen)
01386             continue;
01387 
01388         /* Copy to avoid const on fsm->path. */
01389         te = stpcpy(dn, fsm->path) - 1;
01390         fsm->path = dn;
01391 
01392         /* Remove generated directories. */
01393         /*@-usereleased@*/ /* LCL: te used after release? */
01394         do {
01395             if (*te == '/') {
01396                 *te = '\0';
01397 /*@-compdef@*/
01398                 rc = fsmNext(fsm, IOSM_RMDIR);
01399 /*@=compdef@*/
01400                 *te = '/';
01401             }
01402             if (rc)
01403                 /*@innerbreak@*/ break;
01404             te--;
01405         } while ((te - fsm->path) > fsm->dnlx[dc]);
01406         /*@=usereleased@*/
01407     }
01408     dnli = dnlFreeIterator(dnli);
01409     /*@=observertrans =dependenttrans@*/
01410 
01411     fsm->path = path;
01412     return rc;
01413 }
01414 
01420 static int fsmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t fsm)
01421         /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter,
01422                 fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/
01423         /*@defines fsm->dnlx, fsm->ldn @*/
01424         /*@globals h_errno, fileSystem, internalState @*/
01425         /*@modifies fsm, fileSystem, internalState @*/
01426 {
01427     struct stat * st = &fsm->sb;
01428     struct stat * ost = &fsm->osb;
01429     const char * path = fsm->path;
01430     mode_t st_mode = st->st_mode;
01431     void * dnli = dnlInitIterator(fsm, 0);
01432     char * dn = fsm->rdbuf;
01433     int dc = dnlCount(dnli);
01434     int rc = 0;
01435     size_t i;
01436 
01437     fsm->path = NULL;
01438 
01439     dn[0] = '\0';
01440     fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
01441     /*@-observertrans -dependenttrans@*/
01442     if (fsm->dnlx != NULL)
01443     while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
01444         size_t dnlen = strlen(fsm->path);
01445         char * te;
01446 
01447         dc = dnlIndex(dnli);
01448         if (dc < 0) continue;
01449         fsm->dnlx[dc] = (unsigned short) dnlen;
01450         if (dnlen <= 1)
01451             continue;
01452 
01453         /*@-compdef -nullpass@*/        /* FIX: fsm->ldn not defined ??? */
01454         if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
01455             continue;
01456         /*@=compdef =nullpass@*/
01457 
01458         /* Copy to avoid const on fsm->path. */
01459         (void) stpcpy(dn, fsm->path);
01460         fsm->path = dn;
01461 
01462         /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
01463         (void) urlPath(dn, (const char **)&te);
01464         for (i = 1, te++; *te != '\0'; te++, i++) {
01465             if (*te != '/')
01466                 /*@innercontinue@*/ continue;
01467 
01468             *te = '\0';
01469 
01470             /* Already validated? */
01471             /*@-usedef -compdef -nullpass -nullderef@*/
01472             if (i < fsm->ldnlen &&
01473                 (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
01474                 !strncmp(fsm->path, fsm->ldn, i))
01475             {
01476                 *te = '/';
01477                 /* Move pre-existing path marker forward. */
01478                 fsm->dnlx[dc] = (te - dn);
01479                 /*@innercontinue@*/ continue;
01480             }
01481             /*@=usedef =compdef =nullpass =nullderef@*/
01482 
01483             /* Validate next component of path. */
01484             rc = fsmUNSAFE(fsm, IOSM_LSTAT);
01485             *te = '/';
01486 
01487             /* Directory already exists? */
01488             if (rc == 0 && S_ISDIR(ost->st_mode)) {
01489                 /* Move pre-existing path marker forward. */
01490                 fsm->dnlx[dc] = (te - dn);
01491             } else if (rc == IOSMERR_ENOENT) {
01492                 rpmfi fi = fsmGetFi(fsm);
01493                 *te = '\0';
01494                 st->st_mode = S_IFDIR | (fi->dperms & 07777);
01495                 rc = fsmNext(fsm, IOSM_MKDIR);
01496                 if (!rc) {
01497                     security_context_t scon = NULL;
01498                     /* XXX FIXME? only new dir will have context set. */
01499                     /* Get file security context from patterns. */
01500 /*@-moduncon@*/
01501                     if (!fsm->nofcontexts
01502                      && !matchpathcon(fsm->path, st->st_mode, &scon)
01503                      && scon != NULL)
01504 /*@=moduncon@*/
01505                     {
01506                         fsm->fcontext = scon;
01507                         rc = fsmNext(fsm, IOSM_LSETFCON);
01508                     } else
01509                         fsm->fcontext = NULL;
01510                     if (fsm->fcontext == NULL)
01511                         rpmlog(RPMLOG_DEBUG,
01512                             D_("%s directory created with perms %04o, no context.\n"),
01513                             fsm->path, (unsigned)(st->st_mode & 07777));
01514                     else {
01515                         rpmlog(RPMLOG_DEBUG,
01516                             D_("%s directory created with perms %04o, context %s.\n"),
01517                             fsm->path, (unsigned)(st->st_mode & 07777),
01518                             fsm->fcontext);
01519                         fsm->fcontext = NULL;
01520                         scon = _free(scon);
01521                     }
01522                 }
01523                 *te = '/';
01524             }
01525             if (rc)
01526                 /*@innerbreak@*/ break;
01527         }
01528         if (rc) break;
01529 
01530         /* Save last validated path. */
01531 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01532         if (fsm->ldnalloc < (dnlen + 1)) {
01533             fsm->ldnalloc = dnlen + 100;
01534             fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
01535         }
01536         if (fsm->ldn != NULL) { /* XXX can't happen */
01537             strcpy(fsm->ldn, fsm->path);
01538             fsm->ldnlen = dnlen;
01539         }
01540 /*@=compdef@*/
01541     }
01542     dnli = dnlFreeIterator(dnli);
01543     /*@=observertrans =dependenttrans@*/
01544 
01545     fsm->path = path;
01546     st->st_mode = st_mode;              /* XXX restore st->st_mode */
01547 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01548     return rc;
01549 /*@=compdef@*/
01550 }
01551 
01552 #ifdef  NOTYET
01553 
01558 static int fsmStat(/*@special@*/ /*@partial@*/ IOSM_t fsm)
01559         /*@globals fileSystem, internalState @*/
01560         /*@modifies fsm, fileSystem, internalState @*/
01561 {
01562     int rc = 0;
01563 
01564     if (fsm->path != NULL) {
01565         int saveernno = errno;
01566         rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS)
01567                         ? IOSM_LSTAT : IOSM_STAT));
01568         if (rc == IOSMERR_ENOENT) {
01569             errno = saveerrno;
01570             rc = 0;
01571             fsm->exists = 0;
01572         } else if (rc == 0) {
01573             fsm->exists = 1;
01574         }
01575     } else {
01576         /* Skip %ghost files on build. */
01577         fsm->exists = 0;
01578     }
01579     return rc;
01580 }
01581 #endif
01582 
01583 #define IS_DEV_LOG(_x)  \
01584         ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
01585         !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \
01586         ((_x)[sizeof("/dev/log")-1] == '\0' || \
01587          (_x)[sizeof("/dev/log")-1] == ';'))
01588 
01589 /*@-compmempass@*/
01590 int fsmStage(IOSM_t fsm, iosmFileStage stage)
01591 {
01592 #ifdef  NOTUSED
01593     iosmFileStage prevStage = fsm->stage;
01594     const char * const prev = iosmFileStageString(prevStage);
01595 #endif
01596     const char * const cur = iosmFileStageString(stage);
01597     struct stat * st = &fsm->sb;
01598     struct stat * ost = &fsm->osb;
01599     int saveerrno = errno;
01600     int rc = fsm->rc;
01601     int i;
01602 
01603 #define _fafilter(_a)   \
01604     (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
01605         ? iosmFileActionString(_a) : "")
01606 
01607     if (stage & IOSM_DEAD) {
01608         /* do nothing */
01609     } else if (stage & IOSM_INTERNAL) {
01610         if (fsm->debug && !(stage & IOSM_SYSCALL))
01611             rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n",
01612                 cur,
01613                 (unsigned)st->st_mode, (int)st->st_nlink,
01614                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01615                 (fsm->path ? fsm->path : ""),
01616                 _fafilter(fsm->action));
01617     } else {
01618         const char * apath = NULL;
01619         if (fsm->path)
01620             (void) urlPath(fsm->path, &apath);
01621         fsm->stage = stage;
01622         if (fsm->debug || !(stage & IOSM_VERBOSE))
01623             rpmlog(RPMLOG_DEBUG, "%-8s  %06o%3d (%4d,%4d)%12lu %s %s\n",
01624                 cur,
01625                 (unsigned)st->st_mode, (int)st->st_nlink,
01626                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01627                 (apath ? apath + fsm->astriplen : ""),
01628                 _fafilter(fsm->action));
01629     }
01630 #undef  _fafilter
01631 
01632     switch (stage) {
01633     case IOSM_UNKNOWN:
01634         break;
01635     case IOSM_PKGINSTALL:
01636         while (1) {
01637             /* Clean fsm, free'ing memory. Read next archive header. */
01638             rc = fsmUNSAFE(fsm, IOSM_INIT);
01639 
01640             /* Exit on end-of-payload. */
01641             if (rc == IOSMERR_HDR_TRAILER) {
01642                 rc = 0;
01643                 /*@loopbreak@*/ break;
01644             }
01645 
01646             /* Exit on error. */
01647             if (rc) {
01648                 fsm->postpone = 1;
01649                 (void) fsmNext(fsm, IOSM_UNDO);
01650                 /*@loopbreak@*/ break;
01651             }
01652 
01653             /* Extract file from archive. */
01654             rc = fsmNext(fsm, IOSM_PROCESS);
01655             if (rc) {
01656                 (void) fsmNext(fsm, IOSM_UNDO);
01657                 /*@loopbreak@*/ break;
01658             }
01659 
01660             /* Notify on success. */
01661             (void) fsmNext(fsm, IOSM_NOTIFY);
01662 
01663             rc = fsmNext(fsm, IOSM_FINI);
01664             if (rc) {
01665                 /*@loopbreak@*/ break;
01666             }
01667         }
01668         break;
01669     case IOSM_PKGERASE:
01670     case IOSM_PKGCOMMIT:
01671         while (1) {
01672             /* Clean fsm, free'ing memory. */
01673             rc = fsmUNSAFE(fsm, IOSM_INIT);
01674 
01675             /* Exit on end-of-payload. */
01676             if (rc == IOSMERR_HDR_TRAILER) {
01677                 rc = 0;
01678                 /*@loopbreak@*/ break;
01679             }
01680 
01681             /* Rename/erase next item. */
01682             if (fsmNext(fsm, IOSM_FINI))
01683                 /*@loopbreak@*/ break;
01684         }
01685         break;
01686     case IOSM_PKGBUILD:
01687         while (1) {
01688 
01689             rc = fsmUNSAFE(fsm, IOSM_INIT);
01690 
01691             /* Exit on end-of-payload. */
01692             if (rc == IOSMERR_HDR_TRAILER) {
01693                 rc = 0;
01694                 /*@loopbreak@*/ break;
01695             }
01696 
01697             /* Exit on error. */
01698             if (rc) {
01699                 fsm->postpone = 1;
01700                 (void) fsmNext(fsm, IOSM_UNDO);
01701                 /*@loopbreak@*/ break;
01702             }
01703 
01704             /* Copy file into archive. */
01705             rc = fsmNext(fsm, IOSM_PROCESS);
01706             if (rc) {
01707                 (void) fsmNext(fsm, IOSM_UNDO);
01708                 /*@loopbreak@*/ break;
01709             }
01710 
01711             /* Notify on success. */
01712             (void) fsmNext(fsm, IOSM_NOTIFY);
01713 
01714             if (fsmNext(fsm, IOSM_FINI))
01715                 /*@loopbreak@*/ break;
01716         }
01717 
01718         /* Flush partial sets of hard linked files. */
01719         if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) {
01720             int nlink, j;
01721             while ((fsm->li = fsm->links) != NULL) {
01722                 fsm->links = fsm->li->next;
01723                 fsm->li->next = NULL;
01724 
01725                 /* Re-calculate link count for archive header. */
01726                 for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) {
01727                     if (fsm->li->filex[i] < 0)
01728                         /*@innercontinue@*/ continue;
01729                     nlink++;
01730                     if (j == -1) j = i;
01731                 }
01732                 /* XXX force the contents out as well. */
01733                 if (j != 0) {
01734                     fsm->li->filex[0] = fsm->li->filex[j];
01735                     fsm->li->filex[j] = -1;
01736                 }
01737                 fsm->li->sb.st_nlink = nlink;
01738 
01739                 fsm->sb = fsm->li->sb;  /* structure assignment */
01740                 fsm->osb = fsm->sb;     /* structure assignment */
01741 
01742                 if (!rc) rc = writeLinkedFile(fsm);
01743 
01744                 fsm->li = freeHardLink(fsm->li);
01745             }
01746         }
01747 
01748         if (!rc)
01749             rc = fsmNext(fsm, IOSM_TRAILER);
01750 
01751         break;
01752     case IOSM_CREATE:
01753         fsm->path = _free(fsm->path);
01754         fsm->lpath = _free(fsm->lpath);
01755         fsm->opath = _free(fsm->opath);
01756         fsm->dnlx = _free(fsm->dnlx);
01757 
01758         fsm->ldn = _free(fsm->ldn);
01759         fsm->ldnalloc = fsm->ldnlen = 0;
01760 
01761         fsm->rdsize = fsm->wrsize = 0;
01762         fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
01763         fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
01764         if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
01765             fsm->rdsize = 16 * BUFSIZ;
01766             fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
01767             fsm->wrsize = 16 * BUFSIZ;
01768             fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
01769         }
01770 
01771         fsm->mkdirsdone = 0;
01772         fsm->ix = -1;
01773         fsm->links = NULL;
01774         fsm->li = NULL;
01775         errno = 0;      /* XXX get rid of EBADF */
01776 
01777         /* Detect and create directories not explicitly in package. */
01778         if (fsm->goal == IOSM_PKGINSTALL) {
01779 /*@-compdef@*/
01780             rc = fsmNext(fsm, IOSM_MKDIRS);
01781 /*@=compdef@*/
01782             if (!rc) fsm->mkdirsdone = 1;
01783         }
01784 
01785         break;
01786     case IOSM_INIT:
01787         fsm->path = _free(fsm->path);
01788         fsm->lpath = _free(fsm->lpath);
01789         fsm->postpone = 0;
01790         fsm->diskchecked = fsm->exists = 0;
01791         fsm->subdir = NULL;
01792         fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
01793         fsm->action = FA_UNKNOWN;
01794         fsm->osuffix = NULL;
01795         fsm->nsuffix = NULL;
01796 
01797         if (fsm->goal == IOSM_PKGINSTALL) {
01798             /* Read next header from payload, checking for end-of-payload. */
01799             rc = fsmUNSAFE(fsm, IOSM_NEXT);
01800         }
01801         if (rc) break;
01802 
01803         /* Identify mapping index. */
01804         fsm->ix = ((fsm->goal == IOSM_PKGINSTALL)
01805                 ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
01806 
01807 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST)) {
01808         /* Detect end-of-loop and/or mapping error. */
01809 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) {
01810         if (fsm->ix < 0) {
01811             if (fsm->goal == IOSM_PKGINSTALL) {
01812 #if 0
01813                 rpmlog(RPMLOG_WARNING,
01814                     _("archive file %s was not found in header file list\n"),
01815                         fsm->path);
01816 #endif
01817                 if (fsm->failedFile && *fsm->failedFile == NULL)
01818                     *fsm->failedFile = xstrdup(fsm->path);
01819                 rc = IOSMERR_UNMAPPED_FILE;
01820             } else {
01821                 rc = IOSMERR_HDR_TRAILER;
01822             }
01823             break;
01824         }
01825 }
01826 
01827         /* On non-install, mode must be known so that dirs don't get suffix. */
01828         if (fsm->goal != IOSM_PKGINSTALL) {
01829             rpmfi fi = fsmGetFi(fsm);
01830             st->st_mode = fi->fmodes[fsm->ix];
01831         }
01832 }
01833 
01834         /* Generate file path. */
01835         rc = fsmNext(fsm, IOSM_MAP);
01836         if (rc) break;
01837 
01838         /* Perform lstat/stat for disk file. */
01839 #ifdef  NOTYET
01840         rc = fsmStat(fsm);
01841 #else
01842         if (fsm->path != NULL &&
01843             !(fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))
01844         {
01845             rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & IOSM_FOLLOW_SYMLINKS)
01846                         ? IOSM_LSTAT : IOSM_STAT));
01847             if (rc == IOSMERR_ENOENT) {
01848                 errno = saveerrno;
01849                 rc = 0;
01850                 fsm->exists = 0;
01851             } else if (rc == 0) {
01852                 fsm->exists = 1;
01853             }
01854         } else {
01855             /* Skip %ghost files on build. */
01856             fsm->exists = 0;
01857         }
01858 #endif
01859         fsm->diskchecked = 1;
01860         if (rc) break;
01861 
01862         /* On non-install, the disk file stat is what's remapped. */
01863         if (fsm->goal != IOSM_PKGINSTALL)
01864             *st = *ost;                 /* structure assignment */
01865 
01866         /* Remap file perms, owner, and group. */
01867         rc = fsmMapAttrs(fsm);
01868         if (rc) break;
01869 
01870         fsm->postpone = iosmFileActionSkipped(fsm->action);
01871         if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
01872             /*@-evalorder@*/ /* FIX: saveHardLink can modify fsm */
01873             if (S_ISREG(st->st_mode) && st->st_nlink > 1)
01874                 fsm->postpone = saveHardLink(fsm);
01875             /*@=evalorder@*/
01876         }
01877 if (fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_LIST) fsm->postpone = 1;
01878         break;
01879     case IOSM_PRE:
01880         break;
01881     case IOSM_MAP:
01882         rc = fsmMapPath(fsm);
01883         break;
01884     case IOSM_MKDIRS:
01885         rc = fsmMkdirs(fsm);
01886         break;
01887     case IOSM_RMDIRS:
01888         if (fsm->dnlx)
01889             rc = fsmRmdirs(fsm);
01890         break;
01891     case IOSM_PROCESS:
01892         if (fsm->postpone) {
01893             if (fsm->goal == IOSM_PKGINSTALL) {
01894                 /* XXX Skip over file body, archive headers already done. */
01895                 if (S_ISREG(st->st_mode))
01896                     rc = fsmNext(fsm, IOSM_EAT);
01897             }
01898             break;
01899         }
01900 
01901         if (fsm->goal == IOSM_PKGBUILD) {
01902             if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
01903                 break;
01904             if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
01905                 struct hardLink_s * li, * prev;
01906 
01907 if (!(fsm->mapFlags & IOSM_ALL_HARDLINKS)) break;
01908                 rc = writeLinkedFile(fsm);
01909                 if (rc) break;  /* W2DO? */
01910 
01911                 for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
01912                      if (li == fsm->li)
01913                         /*@loopbreak@*/ break;
01914 
01915                 if (prev == NULL)
01916                     fsm->links = fsm->li->next;
01917                 else
01918                     prev->next = fsm->li->next;
01919                 fsm->li->next = NULL;
01920                 fsm->li = freeHardLink(fsm->li);
01921             } else {
01922                 rc = writeFile(fsm, 1);
01923             }
01924             break;
01925         }
01926 
01927         if (fsm->goal != IOSM_PKGINSTALL)
01928             break;
01929 
01930         if (S_ISREG(st->st_mode) && fsm->lpath != NULL) {
01931             const char * opath = fsm->opath;
01932             char * t = xmalloc(strlen(fsm->lpath+1) + strlen(fsm->suffix) + 1);
01933             (void) stpcpy(t, fsm->lpath+1);
01934              fsm->opath = t;
01935             /* XXX link(fsm->opath, fsm->path) */
01936             rc = fsmNext(fsm, IOSM_LINK);
01937             if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01938                 *fsm->failedFile = xstrdup(fsm->path);
01939             }
01940             fsm->opath = _free(fsm->opath);
01941             fsm->opath = opath;
01942             break;      /* XXX so that delayed hard links get skipped. */
01943         }
01944         if (S_ISREG(st->st_mode)) {
01945             const char * path = fsm->path;
01946             if (fsm->osuffix)
01947                 fsm->path = fsmFsPath(fsm, st, NULL, NULL);
01948             rc = fsmUNSAFE(fsm, IOSM_VERIFY);
01949 
01950             if (rc == 0 && fsm->osuffix) {
01951                 const char * opath = fsm->opath;
01952                 fsm->opath = fsm->path;
01953                 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
01954                 rc = fsmNext(fsm, IOSM_RENAME);
01955                 if (!rc)
01956                     rpmlog(RPMLOG_WARNING,
01957                         _("%s saved as %s\n"),
01958                                 (fsm->opath ? fsm->opath : ""),
01959                                 (fsm->path ? fsm->path : ""));
01960                 fsm->path = _free(fsm->path);
01961                 fsm->opath = opath;
01962             }
01963 
01964             /*@-dependenttrans@*/
01965             fsm->path = path;
01966             /*@=dependenttrans@*/
01967             if (!(rc == IOSMERR_ENOENT)) return rc;
01968             rc = extractRegular(fsm);
01969         } else if (S_ISDIR(st->st_mode)) {
01970             mode_t st_mode = st->st_mode;
01971             rc = fsmUNSAFE(fsm, IOSM_VERIFY);
01972             if (rc == IOSMERR_ENOENT) {
01973                 st->st_mode &= ~07777;          /* XXX abuse st->st_mode */
01974                 st->st_mode |=  00700;
01975                 rc = fsmNext(fsm, IOSM_MKDIR);
01976                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
01977             }
01978         } else if (S_ISLNK(st->st_mode)) {
01979 assert(fsm->lpath != NULL);
01980             /*@=dependenttrans@*/
01981             rc = fsmUNSAFE(fsm, IOSM_VERIFY);
01982             if (rc == IOSMERR_ENOENT)
01983                 rc = fsmNext(fsm, IOSM_SYMLINK);
01984         } else if (S_ISFIFO(st->st_mode)) {
01985             mode_t st_mode = st->st_mode;
01986             /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
01987             rc = fsmUNSAFE(fsm, IOSM_VERIFY);
01988             if (rc == IOSMERR_ENOENT) {
01989                 st->st_mode = 0000;             /* XXX abuse st->st_mode */
01990                 rc = fsmNext(fsm, IOSM_MKFIFO);
01991                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
01992             }
01993         } else if (S_ISCHR(st->st_mode) ||
01994                    S_ISBLK(st->st_mode) ||
01995     /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
01996         {
01997             rc = fsmUNSAFE(fsm, IOSM_VERIFY);
01998             if (rc == IOSMERR_ENOENT)
01999                 rc = fsmNext(fsm, IOSM_MKNOD);
02000         } else {
02001             /* XXX Repackaged payloads may be missing files. */
02002             if (fsm->repackaged)
02003                 break;
02004 
02005             /* XXX Special case /dev/log, which shouldn't be packaged anyways */
02006             if (!IS_DEV_LOG(fsm->path))
02007                 rc = IOSMERR_UNKNOWN_FILETYPE;
02008         }
02009         if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
02010             fsm->li->createdPath = fsm->li->linkIndex;
02011             rc = fsmMakeLinks(fsm);
02012         }
02013         break;
02014     case IOSM_POST:
02015         break;
02016     case IOSM_MKLINKS:
02017         rc = fsmMakeLinks(fsm);
02018         break;
02019     case IOSM_NOTIFY:           /* XXX move from fsm to psm -> tsm */
02020         if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
02021             rpmts ts = fsmGetTs(fsm);
02022             rpmfi fi = fsmGetFi(fsm);
02023             void * ptr;
02024             rpmuint64_t archivePos = fdGetCpioPos(fsm->cfd);
02025             if (archivePos > fi->archivePos) {
02026                 fi->archivePos = (unsigned long long) archivePos;
02027                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS,
02028                         fi->archivePos, fi->archiveSize);
02029             }
02030         }
02031         break;
02032     case IOSM_UNDO:
02033         if (fsm->postpone)
02034             break;
02035         if (fsm->goal == IOSM_PKGINSTALL) {
02036             /* XXX only erase if temp fn w suffix is in use */
02037             if (fsm->sufbuf[0] != '\0')
02038                 (void) fsmNext(fsm,
02039                     (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK));
02040 
02041 #ifdef  NOTYET  /* XXX remove only dirs just created, not all. */
02042             if (fsm->dnlx)
02043                 (void) fsmNext(fsm, IOSM_RMDIRS);
02044 #endif
02045             errno = saveerrno;
02046         }
02047         if (fsm->failedFile && *fsm->failedFile == NULL)
02048             *fsm->failedFile = xstrdup(fsm->path);
02049         break;
02050     case IOSM_FINI:
02051         if (!fsm->postpone && fsm->commit) {
02052             if (fsm->goal == IOSM_PKGINSTALL)
02053                 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
02054                         ? fsmCommitLinks(fsm) : fsmNext(fsm, IOSM_COMMIT));
02055             if (fsm->goal == IOSM_PKGCOMMIT)
02056                 rc = fsmNext(fsm, IOSM_COMMIT);
02057             if (fsm->goal == IOSM_PKGERASE)
02058                 rc = fsmNext(fsm, IOSM_COMMIT);
02059         }
02060         fsm->path = _free(fsm->path);
02061         fsm->lpath = _free(fsm->lpath);
02062         fsm->opath = _free(fsm->opath);
02063         memset(st, 0, sizeof(*st));
02064         memset(ost, 0, sizeof(*ost));
02065         break;
02066     case IOSM_COMMIT:
02067         /* Rename pre-existing modified or unmanaged file. */
02068         if (fsm->osuffix && fsm->diskchecked &&
02069           (fsm->exists || (fsm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))))
02070         {
02071             const char * opath = fsm->opath;
02072             const char * path = fsm->path;
02073             fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
02074             fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
02075             rc = fsmNext(fsm, IOSM_RENAME);
02076             if (!rc) {
02077                 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"),
02078                                 (fsm->opath ? fsm->opath : ""),
02079                                 (fsm->path ? fsm->path : ""));
02080             }
02081             fsm->path = _free(fsm->path);
02082             fsm->path = path;
02083             fsm->opath = _free(fsm->opath);
02084             fsm->opath = opath;
02085         }
02086 
02087         /* Remove erased files. */
02088         if (fsm->goal == IOSM_PKGERASE) {
02089             if (fsm->action == FA_ERASE) {
02090                 rpmfi fi = fsmGetFi(fsm);
02091                 if (S_ISDIR(st->st_mode)) {
02092                     rc = fsmNext(fsm, IOSM_RMDIR);
02093                     if (!rc) break;
02094                     switch (rc) {
02095                     case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
02096                     case IOSMERR_ENOTEMPTY:
02097         /* XXX make sure that build side permits %missingok on directories. */
02098                         if (fsm->fflags & RPMFILE_MISSINGOK)
02099                             /*@innerbreak@*/ break;
02100 
02101                         /* XXX common error message. */
02102                         rpmlog(
02103                             (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
02104                             _("%s rmdir of %s failed: Directory not empty\n"), 
02105                                 rpmfiTypeString(fi), fsm->path);
02106                         /*@innerbreak@*/ break;
02107                     default:
02108                         rpmlog(
02109                             (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
02110                                 _("%s rmdir of %s failed: %s\n"),
02111                                 rpmfiTypeString(fi), fsm->path, strerror(errno));
02112                         /*@innerbreak@*/ break;
02113                     }
02114                 } else {
02115                     rc = fsmNext(fsm, IOSM_UNLINK);
02116                     if (!rc) break;
02117                     switch (rc) {
02118                     case IOSMERR_ENOENT:
02119                         if (fsm->fflags & RPMFILE_MISSINGOK)
02120                             /*@innerbreak@*/ break;
02121                         /*@fallthrough@*/
02122                     default:
02123                         rpmlog(
02124                             (fsm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
02125                                 _(" %s: unlink of %s failed: %s\n"),
02126                                 rpmfiTypeString(fi), fsm->path, strerror(errno));
02127                         /*@innerbreak@*/ break;
02128                     }
02129                 }
02130             }
02131             /* XXX Failure to remove is not (yet) cause for failure. */
02132             if (!fsm->strict_erasures) rc = 0;
02133             break;
02134         }
02135 
02136         /* XXX Special case /dev/log, which shouldn't be packaged anyways */
02137 if (!(fsmGetFi(fsm)->mapflags & IOSM_PAYLOAD_EXTRACT)) {
02138         if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
02139             /* Rename temporary to final file name. */
02140             if (!S_ISDIR(st->st_mode) &&
02141                 (fsm->subdir || fsm->suffix || fsm->nsuffix))
02142             {
02143                 fsm->opath = fsm->path;
02144                 fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
02145                 rc = fsmNext(fsm, IOSM_RENAME);
02146                 if (rc)
02147                         (void) Unlink(fsm->opath);
02148                 else if (fsm->nsuffix) {
02149                     const char * opath = fsmFsPath(fsm, st, NULL, NULL);
02150                     rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
02151                                 (opath ? opath : ""),
02152                                 (fsm->path ? fsm->path : ""));
02153                     opath = _free(opath);
02154                 }
02155                 fsm->opath = _free(fsm->opath);
02156             }
02157             /*
02158              * Set file security context (if not disabled).
02159              */
02160             if (!rc && !getuid()) {
02161                 rc = fsmMapFContext(fsm);
02162                 if (!rc)
02163                     rc = fsmNext(fsm, IOSM_LSETFCON);
02164                 fsm->fcontext = NULL;
02165             }
02166             if (S_ISLNK(st->st_mode)) {
02167                 if (!rc && !getuid())
02168                     rc = fsmNext(fsm, IOSM_LCHOWN);
02169             } else {
02170                 if (!rc && !getuid())
02171                     rc = fsmNext(fsm, IOSM_CHOWN);
02172                 if (!rc)
02173                     rc = fsmNext(fsm, IOSM_CHMOD);
02174                 if (!rc) {
02175                     time_t mtime = st->st_mtime;
02176                     rpmfi fi = fsmGetFi(fsm);
02177                     if (fi->fmtimes)
02178                         st->st_mtime = fi->fmtimes[fsm->ix];
02179                     rc = fsmNext(fsm, IOSM_UTIME);
02180                     st->st_mtime = mtime;
02181                 }
02182             }
02183         }
02184 }
02185 
02186         /* Notify on success. */
02187         if (!rc)                rc = fsmNext(fsm, IOSM_NOTIFY);
02188         else if (fsm->failedFile && *fsm->failedFile == NULL) {
02189             *fsm->failedFile = fsm->path;
02190             fsm->path = NULL;
02191         }
02192         break;
02193     case IOSM_DESTROY:
02194         fsm->path = _free(fsm->path);
02195 
02196         /* Check for hard links missing from payload. */
02197         while ((fsm->li = fsm->links) != NULL) {
02198             fsm->links = fsm->li->next;
02199             fsm->li->next = NULL;
02200             if (fsm->goal == IOSM_PKGINSTALL &&
02201                         fsm->commit && fsm->li->linksLeft)
02202             {
02203                 for (i = 0 ; i < fsm->li->linksLeft; i++) {
02204                     if (fsm->li->filex[i] < 0)
02205                         /*@innercontinue@*/ continue;
02206                     rc = IOSMERR_MISSING_HARDLINK;
02207                     if (fsm->failedFile && *fsm->failedFile == NULL) {
02208                         fsm->ix = fsm->li->filex[i];
02209                         if (!fsmNext(fsm, IOSM_MAP)) {
02210                             *fsm->failedFile = fsm->path;
02211                             fsm->path = NULL;
02212                         }
02213                     }
02214                     /*@loopbreak@*/ break;
02215                 }
02216             }
02217             if (fsm->goal == IOSM_PKGBUILD &&
02218                 (fsm->mapFlags & IOSM_ALL_HARDLINKS))
02219             {
02220                 rc = IOSMERR_MISSING_HARDLINK;
02221             }
02222             fsm->li = freeHardLink(fsm->li);
02223         }
02224         fsm->ldn = _free(fsm->ldn);
02225         fsm->ldnalloc = fsm->ldnlen = 0;
02226         fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
02227         fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
02228         break;
02229     case IOSM_VERIFY:
02230         if (fsm->diskchecked && !fsm->exists) {
02231             rc = IOSMERR_ENOENT;
02232             break;
02233         }
02234         if (S_ISREG(st->st_mode)) {
02235             char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
02236             (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
02237             /*
02238              * XXX HP-UX (and other os'es) don't permit unlink on busy
02239              * XXX files.
02240              */
02241             fsm->opath = fsm->path;
02242             fsm->path = path;
02243             rc = fsmNext(fsm, IOSM_RENAME);
02244             if (!rc)
02245                     (void) fsmNext(fsm, IOSM_UNLINK);
02246             else
02247                     rc = IOSMERR_UNLINK_FAILED;
02248             fsm->path = fsm->opath;
02249             fsm->opath = NULL;
02250             return (rc ? rc : IOSMERR_ENOENT);  /* XXX HACK */
02251             /*@notreached@*/ break;
02252         } else if (S_ISDIR(st->st_mode)) {
02253             if (S_ISDIR(ost->st_mode))          return 0;
02254             if (S_ISLNK(ost->st_mode)) {
02255                 rc = fsmUNSAFE(fsm, IOSM_STAT);
02256                 if (rc == IOSMERR_ENOENT) rc = 0;
02257                 if (rc) break;
02258                 errno = saveerrno;
02259                 if (S_ISDIR(ost->st_mode))      return 0;
02260             }
02261         } else if (S_ISLNK(st->st_mode)) {
02262             if (S_ISLNK(ost->st_mode)) {
02263         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
02264                 rc = fsmUNSAFE(fsm, IOSM_READLINK);
02265                 errno = saveerrno;
02266                 if (rc) break;
02267                 if (!strcmp(fsm->lpath, fsm->rdbuf))    return 0;
02268             }
02269         } else if (S_ISFIFO(st->st_mode)) {
02270             if (S_ISFIFO(ost->st_mode))         return 0;
02271         } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
02272             if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
02273                 (ost->st_rdev == st->st_rdev))  return 0;
02274         } else if (S_ISSOCK(st->st_mode)) {
02275             if (S_ISSOCK(ost->st_mode))         return 0;
02276         }
02277             /* XXX shouldn't do this with commit/undo. */
02278         rc = 0;
02279         if (fsm->stage == IOSM_PROCESS) rc = fsmNext(fsm, IOSM_UNLINK);
02280         if (rc == 0)    rc = IOSMERR_ENOENT;
02281         return (rc ? rc : IOSMERR_ENOENT);      /* XXX HACK */
02282         /*@notreached@*/ break;
02283 
02284     case IOSM_UNLINK:
02285     case IOSM_RENAME:
02286     case IOSM_MKDIR:
02287     case IOSM_RMDIR:
02288     case IOSM_LSETFCON:
02289     case IOSM_CHOWN:
02290     case IOSM_LCHOWN:
02291     case IOSM_CHMOD:
02292     case IOSM_UTIME:
02293     case IOSM_SYMLINK:
02294     case IOSM_LINK:
02295     case IOSM_MKFIFO:
02296     case IOSM_MKNOD:
02297     case IOSM_LSTAT:
02298     case IOSM_STAT:
02299     case IOSM_READLINK:
02300     case IOSM_CHROOT:
02301         rc = iosmStage(fsm, stage);
02302         break;
02303 
02304     case IOSM_NEXT:
02305     case IOSM_EAT:
02306     case IOSM_POS:
02307     case IOSM_PAD:
02308     case IOSM_TRAILER:
02309     case IOSM_HREAD:
02310     case IOSM_HWRITE:
02311     case IOSM_DREAD:
02312     case IOSM_DWRITE:
02313         rc = iosmStage(fsm, stage);
02314         break;
02315 
02316     case IOSM_ROPEN:
02317     case IOSM_READ:
02318     case IOSM_RCLOSE:
02319         rc = iosmStage(fsm, stage);
02320         break;
02321     case IOSM_WOPEN:
02322     case IOSM_WRITE:
02323     case IOSM_WCLOSE:
02324         rc = iosmStage(fsm, stage);
02325         break;
02326 
02327     default:
02328         break;
02329     }
02330 
02331     if (!(stage & IOSM_INTERNAL)) {
02332         fsm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc);
02333     }
02334     return rc;
02335 }
02336 /*@=compmempass@*/