lib/fsm.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio_internal.h>
00009 #include <rpmlib.h>
00010 
00011 #include "cpio.h"
00012 #include "tar.h"
00013 
00014 #include "fsm.h"
00015 #define fsmUNSAFE       fsmStage
00016 
00017 #include "rpmerr.h"
00018 
00019 #define _RPMFI_INTERNAL
00020 #include "rpmfi.h"
00021 #include "rpmte.h"
00022 #include "rpmts.h"
00023 #include "rpmsq.h"
00024 
00025 #include "ugid.h"               /* XXX unameToUid() and gnameToGid() */
00026 
00027 #include "debug.h"
00028 
00029 /*@access FD_t @*/      /* XXX void ptr args */
00030 /*@access FSMI_t @*/
00031 /*@access FSM_t @*/
00032 
00033 /*@access rpmfi @*/
00034 
00035 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00036 
00037 #define _FSM_DEBUG      0
00038 /*@unchecked@*/
00039 int _fsm_debug = _FSM_DEBUG;
00040 
00041 /*@-exportheadervar@*/
00042 /*@unchecked@*/
00043 int _fsm_threads = 0;
00044 /*@=exportheadervar@*/
00045 
00046 /* XXX Failure to remove is not (yet) cause for failure. */
00047 /*@-exportlocal -exportheadervar@*/
00048 /*@unchecked@*/
00049 int strict_erasures = 0;
00050 /*@=exportlocal =exportheadervar@*/
00051 
00052 rpmts fsmGetTs(const FSM_t fsm) {
00053     const FSMI_t iter = fsm->iter;
00054     /*@-compdef -refcounttrans -retexpose -usereleased @*/
00055     return (iter ? iter->ts : NULL);
00056     /*@=compdef =refcounttrans =retexpose =usereleased @*/
00057 }
00058 
00059 rpmfi fsmGetFi(const FSM_t fsm)
00060 {
00061     const FSMI_t iter = fsm->iter;
00062     /*@-compdef -refcounttrans -retexpose -usereleased @*/
00063     return (iter ? iter->fi : NULL);
00064     /*@=compdef =refcounttrans =retexpose =usereleased @*/
00065 }
00066 
00067 #define SUFFIX_RPMORIG  ".rpmorig"
00068 #define SUFFIX_RPMSAVE  ".rpmsave"
00069 #define SUFFIX_RPMNEW   ".rpmnew"
00070 
00079 static /*@only@*//*@null@*/
00080 const char * fsmFsPath(/*@special@*/ /*@null@*/ const FSM_t fsm,
00081                 /*@null@*/ const struct stat * st,
00082                 /*@null@*/ const char * subdir,
00083                 /*@null@*/ const char * suffix)
00084         /*@uses fsm->dirName, fsm->baseName */
00085         /*@*/
00086 {
00087     const char * s = NULL;
00088 
00089     if (fsm) {
00090         char * t;
00091         int nb;
00092         nb = strlen(fsm->dirName) +
00093             (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) +
00094             (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) +
00095             strlen(fsm->baseName) + 1;
00096 /*@-boundswrite@*/
00097         s = t = xmalloc(nb);
00098         t = stpcpy(t, fsm->dirName);
00099         if (st && !S_ISDIR(st->st_mode))
00100             if (subdir) t = stpcpy(t, subdir);
00101         t = stpcpy(t, fsm->baseName);
00102         if (st && !S_ISDIR(st->st_mode))
00103             if (suffix) t = stpcpy(t, suffix);
00104 /*@=boundswrite@*/
00105     }
00106     return s;
00107 }
00108 
00114 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p)
00115         /*@globals fileSystem @*/
00116         /*@modifies fileSystem @*/
00117 {
00118     FSMI_t iter = p;
00119     if (iter) {
00120 /*@-internalglobs@*/ /* XXX rpmswExit() */
00121         iter->ts = rpmtsFree(iter->ts);
00122 /*@=internalglobs@*/
00123         iter->fi = rpmfiUnlink(iter->fi, "mapIterator");
00124     }
00125     return _free(p);
00126 }
00127 
00134 static void *
00135 mapInitIterator(rpmts ts, rpmfi fi)
00136         /*@modifies ts, fi @*/
00137 {
00138     FSMI_t iter = NULL;
00139 
00140     iter = xcalloc(1, sizeof(*iter));
00141     iter->ts = rpmtsLink(ts, "mapIterator");
00142     iter->fi = rpmfiLink(fi, "mapIterator");
00143     iter->reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT);
00144     iter->i = (iter->reverse ? (fi->fc - 1) : 0);
00145     iter->isave = iter->i;
00146     return iter;
00147 }
00148 
00154 static int mapNextIterator(/*@null@*/ void * a)
00155         /*@*/
00156 {
00157     FSMI_t iter = a;
00158     int i = -1;
00159 
00160     if (iter) {
00161         const rpmfi fi = iter->fi;
00162         if (iter->reverse) {
00163             if (iter->i >= 0)   i = iter->i--;
00164         } else {
00165             if (iter->i < fi->fc)       i = iter->i++;
00166         }
00167         iter->isave = i;
00168     }
00169     return i;
00170 }
00171 
00174 /*@-boundsread@*/
00175 static int cpioStrCmp(const void * a, const void * b)
00176         /*@*/
00177 {
00178     const char * aurl = *(const char **)a;
00179     const char * burl = *(const char **)b;
00180     const char * afn = NULL;
00181     const char * bfn = NULL;
00182 
00183     (void) urlPath(aurl, &afn);
00184     (void) urlPath(burl, &bfn);
00185 
00186     /* XXX Some 4+ year old rpm packages have basename only in payloads. */
00187 #ifdef  VERY_OLD_BUGGY_RPM_PACKAGES
00188     if (strchr(afn, '/') == NULL)
00189         bfn = strrchr(bfn, '/') + 1;
00190 #endif
00191 
00192     /* Match rpm-4.0 payloads with ./ prefixes. */
00193     if (afn[0] == '.' && afn[1] == '/') afn += 2;
00194     if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
00195 
00196     /* If either path is absolute, make it relative. */
00197     if (afn[0] == '/')  afn += 1;
00198     if (bfn[0] == '/')  bfn += 1;
00199 
00200     return strcmp(afn, bfn);
00201 }
00202 /*@=boundsread@*/
00203 
00210 /*@-boundsread@*/
00211 static int mapFind(/*@null@*/ FSMI_t iter, const char * fsmPath)
00212         /*@modifies iter @*/
00213 {
00214     int ix = -1;
00215 
00216     if (iter) {
00217         const rpmfi fi = iter->fi;
00218         if (fi && fi->fc > 0 && fi->apath && fsmPath && *fsmPath) {
00219             const char ** p = NULL;
00220 
00221 /*@-boundswrite@*/
00222             if (fi->apath != NULL)
00223                 p = bsearch(&fsmPath, fi->apath, fi->fc, sizeof(fsmPath),
00224                         cpioStrCmp);
00225 /*@=boundswrite@*/
00226             if (p) {
00227                 iter->i = p - fi->apath;
00228                 ix = mapNextIterator(iter);
00229             }
00230         }
00231     }
00232     return ix;
00233 }
00234 /*@=boundsread@*/
00235 
00239 typedef struct dnli_s {
00240     rpmfi fi;
00241 /*@only@*/ /*@null@*/
00242     char * active;
00243     int reverse;
00244     int isave;
00245     int i;
00246 } * DNLI_t;
00247 
00253 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a)
00254         /*@modifies a @*/
00255 {
00256     if (a) {
00257         DNLI_t dnli = (void *)a;
00258         if (dnli->active) free(dnli->active);
00259     }
00260     return _free(a);
00261 }
00262 
00265 static inline int dnlCount(/*@null@*/ const DNLI_t dnli)
00266         /*@*/
00267 {
00268     return (dnli ? dnli->fi->dc : 0);
00269 }
00270 
00273 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli)
00274         /*@*/
00275 {
00276     return (dnli ? dnli->isave : -1);
00277 }
00278 
00285 /*@-boundsread@*/
00286 /*@-usereleased@*/
00287 static /*@only@*/ /*@null@*/
00288 void * dnlInitIterator(/*@special@*/ const FSM_t fsm,
00289                 int reverse)
00290         /*@uses fsm->iter @*/ 
00291         /*@*/
00292 {
00293     rpmfi fi = fsmGetFi(fsm);
00294     const char * dnl;
00295     DNLI_t dnli;
00296     int i, j;
00297 
00298     if (fi == NULL)
00299         return NULL;
00300     dnli = xcalloc(1, sizeof(*dnli));
00301     dnli->fi = fi;
00302     dnli->reverse = reverse;
00303     /*@-branchstate@*/
00304     dnli->i = (reverse ? fi->dc : 0);
00305     /*@=branchstate@*/
00306 
00307     if (fi->dc) {
00308         dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
00309 
00310         /* Identify parent directories not skipped. */
00311 /*@-boundswrite@*/
00312         for (i = 0; i < fi->fc; i++)
00313             if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
00314 /*@=boundswrite@*/
00315 
00316         /* Exclude parent directories that are explicitly included. */
00317         for (i = 0; i < fi->fc; i++) {
00318             int dil, dnlen, bnlen;
00319 
00320             if (!S_ISDIR(fi->fmodes[i]))
00321                 continue;
00322 
00323             dil = fi->dil[i];
00324             dnlen = strlen(fi->dnl[dil]);
00325             bnlen = strlen(fi->bnl[i]);
00326 
00327             for (j = 0; j < fi->dc; j++) {
00328                 int jlen;
00329 
00330                 if (!dnli->active[j] || j == dil)
00331                     /*@innercontinue@*/ continue;
00332                 (void) urlPath(fi->dnl[j], &dnl);
00333                 jlen = strlen(dnl);
00334                 if (jlen != (dnlen+bnlen+1))
00335                     /*@innercontinue@*/ continue;
00336                 if (strncmp(dnl, fi->dnl[dil], dnlen))
00337                     /*@innercontinue@*/ continue;
00338                 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen))
00339                     /*@innercontinue@*/ continue;
00340                 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
00341                     /*@innercontinue@*/ continue;
00342                 /* This directory is included in the package. */
00343 /*@-boundswrite@*/
00344                 dnli->active[j] = 0;
00345 /*@=boundswrite@*/
00346                 /*@innerbreak@*/ break;
00347             }
00348         }
00349 
00350         /* Print only once per package. */
00351         if (!reverse) {
00352             j = 0;
00353             for (i = 0; i < fi->dc; i++) {
00354                 if (!dnli->active[i]) continue;
00355                 if (j == 0) {
00356                     j = 1;
00357                     rpmMessage(RPMMESS_DEBUG,
00358         _("========== Directories not explicitly included in package:\n"));
00359                 }
00360                 (void) urlPath(fi->dnl[i], &dnl);
00361                 rpmMessage(RPMMESS_DEBUG, _("%10d %s\n"), i, dnl);
00362             }
00363             if (j)
00364                 rpmMessage(RPMMESS_DEBUG, "==========\n");
00365         }
00366     }
00367     return dnli;
00368 }
00369 /*@=usereleased@*/
00370 /*@=boundsread@*/
00371 
00377 /*@-boundsread@*/
00378 static /*@observer@*/ /*@null@*/
00379 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli)
00380         /*@modifies dnli @*/
00381 {
00382     const char * dn = NULL;
00383 
00384     if (dnli) {
00385         rpmfi fi = dnli->fi;
00386         int i = -1;
00387 
00388         if (dnli->active)
00389         do {
00390             i = (!dnli->reverse ? dnli->i++ : --dnli->i);
00391         } while (i >= 0 && i < fi->dc && !dnli->active[i]);
00392 
00393         if (i >= 0 && i < fi->dc)
00394             dn = fi->dnl[i];
00395         else
00396             i = -1;
00397         dnli->isave = i;
00398     }
00399     return dn;
00400 }
00401 /*@=boundsread@*/
00402 
00403 static void * fsmThread(void * arg)
00404         /*@globals h_errno, fileSystem, internalState @*/
00405         /*@modifies arg, fileSystem, internalState @*/
00406 {
00407     FSM_t fsm = arg;
00408 /*@-unqualifiedtrans@*/
00409     return ((void *) ((long)fsmStage(fsm, fsm->nstage)));
00410 /*@=unqualifiedtrans@*/
00411 }
00412 
00413 int fsmNext(FSM_t fsm, fileStage nstage)
00414         /*@globals h_errno, fileSystem, internalState @*/
00415         /*@modifies fsm, fileSystem, internalState @*/
00416 {
00417     fsm->nstage = nstage;
00418     if (_fsm_threads)
00419         return rpmsqJoin( rpmsqThread(fsmThread, fsm) );
00420     return fsmStage(fsm, fsm->nstage);
00421 }
00422 
00428 /*@-boundsread@*/
00429 static int saveHardLink(/*@special@*/ /*@partial@*/ FSM_t fsm)
00430         /*@uses fsm->links, fsm->ix, fsm->sb, fsm->goal, fsm->nsuffix @*/
00431         /*@defines fsm->li @*/
00432         /*@releases fsm->path @*/
00433         /*@globals h_errno, fileSystem, internalState @*/
00434         /*@modifies fsm, fileSystem, internalState @*/
00435 {
00436     struct stat * st = &fsm->sb;
00437     int rc = 0;
00438     int ix = -1;
00439     int j;
00440 
00441     /* Find hard link set. */
00442     /*@-branchstate@*/
00443     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
00444         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
00445             break;
00446     }
00447     /*@=branchstate@*/
00448 
00449     /* New hard link encountered, add new link to set. */
00450 /*@-boundswrite@*/
00451     /*@-branchstate@*/
00452     if (fsm->li == NULL) {
00453         fsm->li = xcalloc(1, sizeof(*fsm->li));
00454         fsm->li->next = NULL;
00455         fsm->li->sb = *st;      /* structure assignment */
00456         fsm->li->nlink = st->st_nlink;
00457         fsm->li->linkIndex = fsm->ix;
00458         fsm->li->createdPath = -1;
00459 
00460         fsm->li->filex = xcalloc(st->st_nlink, sizeof(fsm->li->filex[0]));
00461         memset(fsm->li->filex, -1, (st->st_nlink * sizeof(fsm->li->filex[0])));
00462         fsm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*fsm->li->nsuffix));
00463 
00464         if (fsm->goal == FSM_PKGBUILD)
00465             fsm->li->linksLeft = st->st_nlink;
00466         if (fsm->goal == FSM_PKGINSTALL)
00467             fsm->li->linksLeft = 0;
00468 
00469         /*@-kepttrans@*/
00470         fsm->li->next = fsm->links;
00471         /*@=kepttrans@*/
00472         fsm->links = fsm->li;
00473     }
00474     /*@=branchstate@*/
00475 /*@=boundswrite@*/
00476 
00477     if (fsm->goal == FSM_PKGBUILD) --fsm->li->linksLeft;
00478 /*@-boundswrite@*/
00479     fsm->li->filex[fsm->li->linksLeft] = fsm->ix;
00480     /*@-observertrans -dependenttrans@*/
00481     fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
00482     /*@=observertrans =dependenttrans@*/
00483 /*@=boundswrite@*/
00484     if (fsm->goal == FSM_PKGINSTALL) fsm->li->linksLeft++;
00485 
00486     if (fsm->goal == FSM_PKGBUILD)
00487         return (fsm->li->linksLeft > 0);
00488 
00489     if (fsm->goal != FSM_PKGINSTALL)
00490         return 0;
00491 
00492     if (!(st->st_size || fsm->li->linksLeft == st->st_nlink))
00493         return 1;
00494 
00495     /* Here come the bits, time to choose a non-skipped file name. */
00496     {   rpmfi fi = fsmGetFi(fsm);
00497 
00498         for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
00499             ix = fsm->li->filex[j];
00500             if (ix < 0 || XFA_SKIPPING(fi->actions[ix]))
00501                 continue;
00502             break;
00503         }
00504     }
00505 
00506     /* Are all links skipped or not encountered yet? */
00507     if (ix < 0 || j < 0)
00508         return 1;       /* XXX W2DO? */
00509 
00510     /* Save the non-skipped file name and map index. */
00511     fsm->li->linkIndex = j;
00512     fsm->path = _free(fsm->path);
00513     fsm->ix = ix;
00514     rc = fsmNext(fsm, FSM_MAP);
00515     return rc;
00516 }
00517 /*@=boundsread@*/
00518 
00524 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li)
00525         /*@modifies li @*/
00526 {
00527     if (li) {
00528         li->nsuffix = _free(li->nsuffix);       /* XXX elements are shared */
00529         li->filex = _free(li->filex);
00530     }
00531     return _free(li);
00532 }
00533 
00534 FSM_t newFSM(void)
00535 {
00536     FSM_t fsm = xcalloc(1, sizeof(*fsm));
00537     return fsm;
00538 }
00539 
00540 FSM_t freeFSM(FSM_t fsm)
00541 {
00542     if (fsm) {
00543         fsm->path = _free(fsm->path);
00544         /*@-branchstate@*/
00545         while ((fsm->li = fsm->links) != NULL) {
00546             fsm->links = fsm->li->next;
00547             fsm->li->next = NULL;
00548             fsm->li = freeHardLink(fsm->li);
00549         }
00550         /*@=branchstate@*/
00551         fsm->dnlx = _free(fsm->dnlx);
00552         fsm->ldn = _free(fsm->ldn);
00553         fsm->iter = mapFreeIterator(fsm->iter);
00554     }
00555     return _free(fsm);
00556 }
00557 
00558 int fsmSetup(FSM_t fsm, fileStage goal, const char * afmt,
00559                 const rpmts ts, const rpmfi fi, FD_t cfd,
00560                 unsigned int * archiveSize, const char ** failedFile)
00561 {
00562     size_t pos = 0;
00563     int rc, ec = 0;
00564 
00565 /*@+voidabstract -nullpass@*/
00566 if (_fsm_debug < 0)
00567 fprintf(stderr, "--> %s(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", __FUNCTION__, fsm, goal, afmt, (void *)ts, fi, cfd, archiveSize, failedFile);
00568 /*@=voidabstract =nullpass@*/
00569 
00570     if (fsm->headerRead == NULL) {
00571         if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) {
00572 if (_fsm_debug < 0)
00573 fprintf(stderr, "\ttar vectors set\n");
00574             fsm->headerRead = &tarHeaderRead;
00575             fsm->headerWrite = &tarHeaderWrite;
00576             fsm->trailerWrite = &tarTrailerWrite;
00577             fsm->blksize = TAR_BLOCK_SIZE;
00578         } else  {
00579 if (_fsm_debug < 0)
00580 fprintf(stderr, "\tcpio vectors set\n");
00581             fsm->headerRead = &cpioHeaderRead;
00582             fsm->headerWrite = &cpioHeaderWrite;
00583             fsm->trailerWrite = &cpioTrailerWrite;
00584             fsm->blksize = 4;
00585         }
00586     }
00587 
00588     fsm->goal = goal;
00589     if (cfd != NULL) {
00590         fsm->cfd = fdLink(cfd, "persist (fsm)");
00591         pos = fdGetCpioPos(fsm->cfd);
00592         fdSetCpioPos(fsm->cfd, 0);
00593     }
00594     fsm->iter = mapInitIterator(ts, fi);
00595 
00596     if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
00597         void * ptr;
00598         fi->archivePos = 0;
00599         ptr = rpmtsNotify(ts, fi->te,
00600                 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize);
00601     }
00602 
00603 /*@-boundswrite@*/
00604     /*@-assignexpose@*/
00605     fsm->archiveSize = archiveSize;
00606     if (fsm->archiveSize)
00607         *fsm->archiveSize = 0;
00608     fsm->failedFile = failedFile;
00609     if (fsm->failedFile)
00610         *fsm->failedFile = NULL;
00611     /*@=assignexpose@*/
00612 /*@=boundswrite@*/
00613 
00614     memset(fsm->sufbuf, 0, sizeof(fsm->sufbuf));
00615     if (fsm->goal == FSM_PKGINSTALL) {
00616         if (ts && rpmtsGetTid(ts) != -1)
00617             sprintf(fsm->sufbuf, ";%08x", (unsigned)rpmtsGetTid(ts));
00618     }
00619 
00620     ec = fsm->rc = 0;
00621     rc = fsmUNSAFE(fsm, FSM_CREATE);
00622     if (rc && !ec) ec = rc;
00623 
00624     rc = fsmUNSAFE(fsm, fsm->goal);
00625     if (rc && !ec) ec = rc;
00626 
00627 /*@-boundswrite@*/
00628     if (fsm->archiveSize && ec == 0)
00629         *fsm->archiveSize = (fdGetCpioPos(fsm->cfd) - pos);
00630 /*@=boundswrite@*/
00631 
00632 /*@-nullstate@*/ /* FIX: *fsm->failedFile may be NULL */
00633    return ec;
00634 /*@=nullstate@*/
00635 }
00636 
00637 int fsmTeardown(FSM_t fsm)
00638 {
00639     int rc = fsm->rc;
00640 
00641 if (_fsm_debug < 0)
00642 fprintf(stderr, "--> %s(%p)\n", __FUNCTION__, fsm);
00643     if (!rc)
00644         rc = fsmUNSAFE(fsm, FSM_DESTROY);
00645 
00646     fsm->iter = mapFreeIterator(fsm->iter);
00647     if (fsm->cfd != NULL) {
00648         fsm->cfd = fdFree(fsm->cfd, "persist (fsm)");
00649         fsm->cfd = NULL;
00650     }
00651     fsm->failedFile = NULL;
00652     return rc;
00653 }
00654 
00655 static int fsmMapFContext(FSM_t fsm)
00656         /*@modifies fsm @*/
00657 {
00658     rpmts ts = fsmGetTs(fsm);
00659     rpmfi fi = fsmGetFi(fsm);
00660     struct stat * st = &fsm->sb;
00661 
00662     /*
00663      * Find file security context (if not disabled).
00664      */
00665     fsm->fcontext = NULL;
00666     if (ts != NULL && rpmtsSELinuxEnabled(ts) == 1 &&
00667         !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS))
00668     {
00669         rpmsx sx = rpmtsREContext(ts);
00670 
00671         if (sx != NULL) {
00672             /* Get file security context from patterns. */
00673             fsm->fcontext = rpmsxFContext(sx, fsm->path, st->st_mode);
00674             sx = rpmsxFree(sx);
00675         } else {
00676             int i = fsm->ix;
00677 
00678             /* Get file security context from package. */
00679             if (fi && i >= 0 && i < fi->fc)
00680                 fsm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL);
00681         }
00682     }
00683     return 0;
00684 }
00685 
00686 int fsmMapPath(FSM_t fsm)
00687 {
00688     rpmfi fi = fsmGetFi(fsm);   /* XXX const except for fstates */
00689     int rc = 0;
00690     int i;
00691 
00692     fsm->osuffix = NULL;
00693     fsm->nsuffix = NULL;
00694     fsm->astriplen = 0;
00695     fsm->action = FA_UNKNOWN;
00696     fsm->mapFlags = fi->mapflags;
00697 
00698     i = fsm->ix;
00699     if (fi && i >= 0 && i < fi->fc) {
00700 
00701 /*@-boundsread@*/
00702         fsm->astriplen = fi->astriplen;
00703         fsm->action = (fi->actions ? fi->actions[i] : fi->action);
00704         fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
00705         fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
00706 
00707         /* src rpms have simple base name in payload. */
00708         fsm->dirName = fi->dnl[fi->dil[i]];
00709         fsm->baseName = fi->bnl[i];
00710 /*@=boundsread@*/
00711 
00712 /*@-boundswrite@*/
00713         switch (fsm->action) {
00714         case FA_SKIP:
00715             break;
00716         case FA_UNKNOWN:
00717             break;
00718 
00719         case FA_COPYOUT:
00720             break;
00721         case FA_COPYIN:
00722         case FA_CREATE:
00723 assert(rpmteType(fi->te) == TR_ADDED);
00724             break;
00725 
00726         case FA_SKIPNSTATE:
00727             if (fi->fstates && rpmteType(fi->te) == TR_ADDED)
00728                 fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
00729             break;
00730 
00731         case FA_SKIPNETSHARED:
00732             if (fi->fstates && rpmteType(fi->te) == TR_ADDED)
00733                 fi->fstates[i] = RPMFILE_STATE_NETSHARED;
00734             break;
00735 
00736         case FA_SKIPCOLOR:
00737             if (fi->fstates && rpmteType(fi->te) == TR_ADDED)
00738                 fi->fstates[i] = RPMFILE_STATE_WRONGCOLOR;
00739             break;
00740 
00741         case FA_BACKUP:
00742             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00743             switch (rpmteType(fi->te)) {
00744             case TR_ADDED:
00745                 fsm->osuffix = SUFFIX_RPMORIG;
00746                 /*@innerbreak@*/ break;
00747             case TR_REMOVED:
00748                 fsm->osuffix = SUFFIX_RPMSAVE;
00749                 /*@innerbreak@*/ break;
00750             }
00751             break;
00752 
00753         case FA_ALTNAME:
00754 assert(rpmteType(fi->te) == TR_ADDED);
00755             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00756                 fsm->nsuffix = SUFFIX_RPMNEW;
00757             break;
00758 
00759         case FA_SAVE:
00760 assert(rpmteType(fi->te) == TR_ADDED);
00761             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00762                 fsm->osuffix = SUFFIX_RPMSAVE;
00763             break;
00764         case FA_ERASE:
00765 #if 0   /* XXX is this a genhdlist fix? */
00766             assert(rpmteType(fi->te) == TR_REMOVED);
00767 #endif
00768             /*
00769              * XXX TODO: %ghost probably shouldn't be removed, but that changes
00770              * legacy rpm behavior.
00771              */
00772             break;
00773         default:
00774             break;
00775         }
00776 /*@=boundswrite@*/
00777 
00778         if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
00779             const struct stat * st = &fsm->sb;
00780             fsm->path = _free(fsm->path);
00781             fsm->path = fsmFsPath(fsm, st, fsm->subdir,
00782                 (fsm->suffix ? fsm->suffix : fsm->nsuffix));
00783         }
00784     }
00785     return rc;
00786 }
00787 
00788 int fsmMapAttrs(FSM_t fsm)
00789 {
00790     struct stat * st = &fsm->sb;
00791     rpmfi fi = fsmGetFi(fsm);
00792     int i = fsm->ix;
00793 
00794     if (fi && i >= 0 && i < fi->fc) {
00795         mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
00796         mode_t finalMode = (fi->fmodes ? fi->fmodes[i] : perms);
00797         dev_t finalRdev = (fi->frdevs ? fi->frdevs[i] : 0);
00798         int_32 finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
00799         uid_t uid = fi->uid;
00800         gid_t gid = fi->gid;
00801 
00802         if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
00803             if (fsm->goal == FSM_PKGINSTALL)
00804                 rpmMessage(RPMMESS_WARNING,
00805                     _("user %s does not exist - using root\n"), fi->fuser[i]);
00806             uid = 0;
00807             finalMode &= ~S_ISUID;      /* turn off suid bit */
00808         }
00809 
00810         if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
00811             if (fsm->goal == FSM_PKGINSTALL)
00812                 rpmMessage(RPMMESS_WARNING,
00813                     _("group %s does not exist - using root\n"), fi->fgroup[i]);
00814             gid = 0;
00815             finalMode &= ~S_ISGID;      /* turn off sgid bit */
00816         }
00817 
00818         if (fsm->mapFlags & CPIO_MAP_MODE)
00819             st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
00820         if (fsm->mapFlags & CPIO_MAP_TYPE) {
00821             st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
00822             if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00823             && st->st_nlink == 0)
00824                 st->st_nlink = 1;
00825             st->st_rdev = finalRdev;
00826             st->st_mtime = finalMtime;
00827         }
00828         if (fsm->mapFlags & CPIO_MAP_UID)
00829             st->st_uid = uid;
00830         if (fsm->mapFlags & CPIO_MAP_GID)
00831             st->st_gid = gid;
00832 
00833         {   rpmts ts = fsmGetTs(fsm);
00834 
00835             /*
00836              * Set file digest (if not disabled).
00837              */
00838             if (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS)) {
00839                 fsm->fdigestalgo = fi->digestalgo;
00840                 fsm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL);
00841                 fsm->digestlen = fi->digestlen;
00842                 fsm->digest = (fi->digests ? (fi->digests + (fsm->digestlen * i)) : NULL);
00843             } else {
00844                 fsm->fdigestalgo = 0;
00845                 fsm->fdigest = NULL;
00846                 fsm->digestlen = 0;
00847                 fsm->digest = NULL;
00848             }
00849         }
00850 
00851     }
00852     return 0;
00853 }
00854 
00860 /*@-compdef@*/
00861 static int extractRegular(/*@special@*/ FSM_t fsm)
00862         /*@uses fsm->fdigest, fsm->digest, fsm->sb, fsm->wfd  @*/
00863         /*@globals h_errno, fileSystem, internalState @*/
00864         /*@modifies fsm, fileSystem, internalState @*/
00865 {
00866     const struct stat * st = &fsm->sb;
00867     int left = st->st_size;
00868     int rc = 0;
00869 
00870     rc = fsmNext(fsm, FSM_WOPEN);
00871     if (rc)
00872         goto exit;
00873 
00874     if (st->st_size > 0 && (fsm->fdigest != NULL || fsm->digest != NULL))
00875         fdInitDigest(fsm->wfd, fsm->fdigestalgo, 0);
00876 
00877     while (left) {
00878 
00879         fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
00880         rc = fsmNext(fsm, FSM_DREAD);
00881         if (rc)
00882             goto exit;
00883 
00884         rc = fsmNext(fsm, FSM_WRITE);
00885         if (rc)
00886             goto exit;
00887 
00888         left -= fsm->wrnb;
00889 
00890         /* Notify iff progress, completion is done elsewhere */
00891         if (!rc && left)
00892             (void) fsmNext(fsm, FSM_NOTIFY);
00893     }
00894 
00895     if (st->st_size > 0 && (fsm->fdigest || fsm->digest)) {
00896         void * digest = NULL;
00897         int asAscii = (fsm->digest == NULL ? 1 : 0);
00898 
00899         (void) Fflush(fsm->wfd);
00900         fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii);
00901 
00902         if (digest == NULL) {
00903             rc = CPIOERR_DIGEST_MISMATCH;
00904             goto exit;
00905         }
00906 
00907         if (fsm->digest != NULL) {
00908             if (memcmp(digest, fsm->digest, fsm->digestlen))
00909                 rc = CPIOERR_DIGEST_MISMATCH;
00910         } else {
00911             if (strcmp(digest, fsm->fdigest))
00912                 rc = CPIOERR_DIGEST_MISMATCH;
00913         }
00914         digest = _free(digest);
00915     }
00916 
00917 exit:
00918     (void) fsmNext(fsm, FSM_WCLOSE);
00919     return rc;
00920 }
00921 /*@=compdef@*/
00922 
00929 /*@-compdef -compmempass@*/
00930 static int writeFile(/*@special@*/ /*@partial@*/ FSM_t fsm, int writeData)
00931         /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/
00932         /*@globals h_errno, fileSystem, internalState @*/
00933         /*@modifies fsm, fileSystem, internalState @*/
00934 {
00935     const char * path = fsm->path;
00936     const char * opath = fsm->opath;
00937     struct stat * st = &fsm->sb;
00938     struct stat * ost = &fsm->osb;
00939     size_t left;
00940     int xx;
00941     int rc;
00942 
00943     st->st_size = (writeData ? ost->st_size : 0);
00944 
00945     /*@-branchstate@*/
00946     if (S_ISDIR(st->st_mode)) {
00947         st->st_size = 0;
00948     } else if (S_ISLNK(st->st_mode)) {
00949         /*
00950          * While linux puts the size of a symlink in the st_size field,
00951          * I don't think that's a specified standard.
00952          */
00953         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
00954         rc = fsmUNSAFE(fsm, FSM_READLINK);
00955         if (rc) goto exit;
00956         st->st_size = fsm->rdnb;
00957         fsm->lpath = xstrdup(fsm->rdbuf);       /* XXX save readlink return. */
00958     }
00959     /*@=branchstate@*/
00960 
00961     if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) {
00962 /*@-boundswrite@*/
00963         int nb = strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof(".");
00964         char * t = alloca(nb);
00965         *t = '\0';
00966         fsm->path = t;
00967         if (fsm->mapFlags & CPIO_MAP_ADDDOT)
00968             *t++ = '.';
00969         t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName);
00970 /*@=boundswrite@*/
00971     } else if (fsm->mapFlags & CPIO_MAP_PATH) {
00972         rpmfi fi = fsmGetFi(fsm);
00973         if (fi->apath) {
00974             const char * apath = NULL;
00975             (void) urlPath(fi->apath[fsm->ix], &apath);
00976             fsm->path = apath + fi->striplen;
00977         } else
00978             fsm->path = fi->bnl[fsm->ix];
00979     }
00980 
00981     rc = fsmNext(fsm, FSM_HWRITE);
00982     fsm->path = path;
00983     if (rc) goto exit;
00984 
00985     if (writeData && S_ISREG(st->st_mode)) {
00986 #if HAVE_MMAP
00987         char * rdbuf = NULL;
00988         void * mapped = (void *)-1;
00989         size_t nmapped = 0;
00990         /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
00991         int use_mmap = (st->st_size <= 0x07ffffff);
00992 #endif
00993 
00994         rc = fsmNext(fsm, FSM_ROPEN);
00995         if (rc) goto exit;
00996 
00997         /* XXX unbuffered mmap generates *lots* of fdio debugging */
00998 #if HAVE_MMAP
00999         if (use_mmap) {
01000             mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
01001             if (mapped != (void *)-1) {
01002                 rdbuf = fsm->rdbuf;
01003                 fsm->rdbuf = (char *) mapped;
01004                 fsm->rdlen = nmapped = st->st_size;
01005 #if defined(MADV_DONTNEED)
01006                 xx = madvise(mapped, nmapped, MADV_DONTNEED);
01007 #endif
01008             }
01009         }
01010 #endif
01011 
01012         left = st->st_size;
01013 
01014         while (left) {
01015 #if HAVE_MMAP
01016           if (mapped != (void *)-1) {
01017             fsm->rdnb = nmapped;
01018           } else
01019 #endif
01020           {
01021             fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
01022             rc = fsmNext(fsm, FSM_READ);
01023             if (rc) goto exit;
01024           }
01025 
01026             /* XXX DWRITE uses rdnb for I/O length. */
01027             rc = fsmNext(fsm, FSM_DWRITE);
01028             if (rc) goto exit;
01029 
01030             left -= fsm->wrnb;
01031         }
01032 
01033 #if HAVE_MMAP
01034 /*@-branchstate@*/
01035         if (mapped != (void *)-1) {
01036             xx = msync(mapped, nmapped, MS_ASYNC);
01037 #if defined(MADV_DONTNEED)
01038             xx = madvise(mapped, nmapped, MADV_DONTNEED);
01039 #endif
01040 /*@-noeffect@*/
01041             xx = munmap(mapped, nmapped);
01042 /*@=noeffect@*/
01043             fsm->rdbuf = rdbuf;
01044         }
01045 /*@=branchstate@*/
01046 #endif
01047 
01048     }
01049 
01050     rc = fsmNext(fsm, FSM_PAD);
01051     if (rc) goto exit;
01052 
01053     rc = 0;
01054 
01055 exit:
01056     if (fsm->rfd != NULL)
01057         (void) fsmNext(fsm, FSM_RCLOSE);
01058 /*@-dependenttrans@*/
01059     fsm->opath = opath;
01060     fsm->path = path;
01061 /*@=dependenttrans@*/
01062     return rc;
01063 }
01064 /*@=compdef =compmempass@*/
01065 
01071 static int writeLinkedFile(/*@special@*/ /*@partial@*/ FSM_t fsm)
01072         /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/
01073         /*@globals h_errno, fileSystem, internalState @*/
01074         /*@modifies fsm, fileSystem, internalState @*/
01075 {
01076     const char * path = fsm->path;
01077     const char * lpath = fsm->lpath;
01078     const char * nsuffix = fsm->nsuffix;
01079     int iterIndex = fsm->ix;
01080     int ec = 0;
01081     int rc;
01082     int i;
01083     const char * linkpath = NULL;
01084     int firstfile = 1;
01085 
01086     fsm->path = NULL;
01087     fsm->lpath = NULL;
01088     fsm->nsuffix = NULL;
01089     fsm->ix = -1;
01090 
01091 /*@-boundswrite@*/
01092 /*@-branchstate@*/
01093     for (i = fsm->li->nlink - 1; i >= 0; i--) {
01094 
01095         if (fsm->li->filex[i] < 0) continue;
01096 
01097         fsm->ix = fsm->li->filex[i];
01098 /*@-compdef@*/
01099         rc = fsmNext(fsm, FSM_MAP);
01100 /*@=compdef@*/
01101 
01102         /* XXX tar and cpio have to do things differently. */
01103         if (fsm->headerWrite == tarHeaderWrite) {
01104             if (firstfile) {
01105                 const char * apath = NULL;
01106                 char *t;
01107                 (void) urlPath(fsm->path, &apath);
01108                 /* Remove the buildroot prefix. */
01109                 t = xmalloc(sizeof(".") + strlen(apath + fsm->astriplen));
01110                 (void) stpcpy( stpcpy(t, "."), apath + fsm->astriplen);
01111                 linkpath = t;
01112                 firstfile = 0;
01113             } else
01114                 fsm->lpath = linkpath;
01115 
01116             /* Write data after first link for tar. */
01117             rc = writeFile(fsm, (fsm->lpath == NULL));
01118         } else {
01119             /* Write data after last link for cpio. */
01120             rc = writeFile(fsm, (i == 0));
01121         }
01122         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01123             ec = rc;
01124             *fsm->failedFile = xstrdup(fsm->path);
01125         }
01126 
01127         fsm->path = _free(fsm->path);
01128         fsm->li->filex[i] = -1;
01129     }
01130 /*@=branchstate@*/
01131 /*@=boundswrite@*/
01132 
01133 /*@-dependenttrans@*/
01134     linkpath = _free(linkpath);
01135 /*@=dependenttrans@*/
01136     fsm->ix = iterIndex;
01137     fsm->nsuffix = nsuffix;
01138     fsm->lpath = lpath;
01139     fsm->path = path;
01140     return ec;
01141 }
01142 
01148 /*@-boundsread@*/
01149 /*@-compdef@*/
01150 static int fsmMakeLinks(/*@special@*/ /*@partial@*/ FSM_t fsm)
01151         /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/
01152         /*@globals h_errno, fileSystem, internalState @*/
01153         /*@modifies fsm, fileSystem, internalState @*/
01154 {
01155     const char * path = fsm->path;
01156     const char * opath = fsm->opath;
01157     const char * nsuffix = fsm->nsuffix;
01158     int iterIndex = fsm->ix;
01159     int ec = 0;
01160     int rc;
01161     int i;
01162 
01163     fsm->path = NULL;
01164     fsm->opath = NULL;
01165     fsm->nsuffix = NULL;
01166     fsm->ix = -1;
01167 
01168     fsm->ix = fsm->li->filex[fsm->li->createdPath];
01169     rc = fsmNext(fsm, FSM_MAP);
01170     fsm->opath = fsm->path;
01171     fsm->path = NULL;
01172     /*@-branchstate@*/
01173     for (i = 0; i < fsm->li->nlink; i++) {
01174         if (fsm->li->filex[i] < 0) continue;
01175         if (fsm->li->createdPath == i) continue;
01176 
01177         fsm->ix = fsm->li->filex[i];
01178         fsm->path = _free(fsm->path);
01179         rc = fsmNext(fsm, FSM_MAP);
01180         if (XFA_SKIPPING(fsm->action)) continue;
01181 
01182         rc = fsmUNSAFE(fsm, FSM_VERIFY);
01183         if (!rc) continue;
01184         if (!(rc == CPIOERR_ENOENT)) break;
01185 
01186         /* XXX link(fsm->opath, fsm->path) */
01187         rc = fsmNext(fsm, FSM_LINK);
01188         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01189             ec = rc;
01190 /*@-boundswrite@*/
01191             *fsm->failedFile = xstrdup(fsm->path);
01192 /*@=boundswrite@*/
01193         }
01194 
01195         fsm->li->linksLeft--;
01196     }
01197     /*@=branchstate@*/
01198     fsm->path = _free(fsm->path);
01199     fsm->opath = _free(fsm->opath);
01200 
01201     fsm->ix = iterIndex;
01202     fsm->nsuffix = nsuffix;
01203     fsm->path = path;
01204     fsm->opath = opath;
01205     return ec;
01206 }
01207 /*@=compdef@*/
01208 /*@=boundsread@*/
01209 
01215 /*@-compdef@*/
01216 static int fsmCommitLinks(/*@special@*/ /*@partial@*/ FSM_t fsm)
01217         /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb,
01218                 fsm->li, fsm->links @*/
01219         /*@globals h_errno, fileSystem, internalState @*/
01220         /*@modifies fsm, fileSystem, internalState @*/
01221 {
01222     const char * path = fsm->path;
01223     const char * nsuffix = fsm->nsuffix;
01224     int iterIndex = fsm->ix;
01225     struct stat * st = &fsm->sb;
01226     int rc = 0;
01227     int i;
01228 
01229     fsm->path = NULL;
01230     fsm->nsuffix = NULL;
01231     fsm->ix = -1;
01232 
01233     /*@-branchstate@*/
01234     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
01235         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
01236             break;
01237     }
01238     /*@=branchstate@*/
01239 
01240 /*@-boundswrite@*/
01241     for (i = 0; i < fsm->li->nlink; i++) {
01242         if (fsm->li->filex[i] < 0) continue;
01243         fsm->ix = fsm->li->filex[i];
01244         rc = fsmNext(fsm, FSM_MAP);
01245         if (!XFA_SKIPPING(fsm->action))
01246             rc = fsmNext(fsm, FSM_COMMIT);
01247         fsm->path = _free(fsm->path);
01248         fsm->li->filex[i] = -1;
01249     }
01250 /*@=boundswrite@*/
01251 
01252     fsm->ix = iterIndex;
01253     fsm->nsuffix = nsuffix;
01254     fsm->path = path;
01255     return rc;
01256 }
01257 /*@=compdef@*/
01258 
01264 static int fsmRmdirs(/*@special@*/ /*@partial@*/ FSM_t fsm)
01265         /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/
01266         /*@globals h_errno, fileSystem, internalState @*/
01267         /*@modifies fsm, fileSystem, internalState @*/
01268 {
01269     const char * path = fsm->path;
01270     void * dnli = dnlInitIterator(fsm, 1);
01271     char * dn = fsm->rdbuf;
01272     int dc = dnlCount(dnli);
01273     int rc = 0;
01274 
01275     fsm->path = NULL;
01276 /*@-boundswrite@*/
01277     dn[0] = '\0';
01278     /*@-observertrans -dependenttrans@*/
01279     if (fsm->ldn != NULL && fsm->dnlx != NULL)
01280     while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
01281         int dnlen = strlen(fsm->path);
01282         char * te;
01283 
01284         dc = dnlIndex(dnli);
01285         if (fsm->dnlx[dc] < 1 || fsm->dnlx[dc] >= dnlen)
01286             continue;
01287 
01288         /* Copy to avoid const on fsm->path. */
01289         te = stpcpy(dn, fsm->path) - 1;
01290         fsm->path = dn;
01291 
01292         /* Remove generated directories. */
01293         /*@-usereleased@*/ /* LCL: te used after release? */
01294         do {
01295             if (*te == '/') {
01296                 *te = '\0';
01297 /*@-compdef@*/
01298                 rc = fsmNext(fsm, FSM_RMDIR);
01299 /*@=compdef@*/
01300                 *te = '/';
01301             }
01302             if (rc)
01303                 /*@innerbreak@*/ break;
01304             te--;
01305         } while ((te - fsm->path) > fsm->dnlx[dc]);
01306         /*@=usereleased@*/
01307     }
01308 /*@=boundswrite@*/
01309     dnli = dnlFreeIterator(dnli);
01310     /*@=observertrans =dependenttrans@*/
01311 
01312     fsm->path = path;
01313     return rc;
01314 }
01315 
01321 static int fsmMkdirs(/*@special@*/ /*@partial@*/ FSM_t fsm)
01322         /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter,
01323                 fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/
01324         /*@defines fsm->dnlx, fsm->ldn @*/
01325         /*@globals h_errno, fileSystem, internalState @*/
01326         /*@modifies fsm, fileSystem, internalState @*/
01327 {
01328     struct stat * st = &fsm->sb;
01329     struct stat * ost = &fsm->osb;
01330     const char * path = fsm->path;
01331     mode_t st_mode = st->st_mode;
01332     void * dnli = dnlInitIterator(fsm, 0);
01333     char * dn = fsm->rdbuf;
01334     int dc = dnlCount(dnli);
01335     int rc = 0;
01336     int i;
01337 /*@-compdef@*/
01338     rpmts ts = fsmGetTs(fsm);
01339 /*@=compdef@*/
01340     rpmsx sx = NULL;
01341 
01342     /* XXX Set file contexts on non-packaged dirs iff selinux enabled. */
01343     if (ts != NULL && rpmtsSELinuxEnabled(ts) == 1 &&
01344       !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS))
01345         sx = rpmtsREContext(ts);
01346 
01347     fsm->path = NULL;
01348 
01349 /*@-boundswrite@*/
01350     dn[0] = '\0';
01351     fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
01352     /*@-observertrans -dependenttrans@*/
01353     if (fsm->dnlx != NULL)
01354     while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
01355         int dnlen = strlen(fsm->path);
01356         char * te;
01357 
01358         dc = dnlIndex(dnli);
01359         if (dc < 0) continue;
01360         fsm->dnlx[dc] = dnlen;
01361         if (dnlen <= 1)
01362             continue;
01363 
01364         /*@-compdef -nullpass@*/        /* FIX: fsm->ldn not defined ??? */
01365         if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
01366             continue;
01367         /*@=compdef =nullpass@*/
01368 
01369         /* Copy to avoid const on fsm->path. */
01370         (void) stpcpy(dn, fsm->path);
01371         fsm->path = dn;
01372 
01373         /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
01374         (void) urlPath(dn, (const char **)&te);
01375         for (i = 1, te++; *te != '\0'; te++, i++) {
01376             if (*te != '/')
01377                 /*@innercontinue@*/ continue;
01378 
01379             *te = '\0';
01380 
01381             /* Already validated? */
01382             /*@-usedef -compdef -nullpass -nullderef@*/
01383             if (i < fsm->ldnlen &&
01384                 (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
01385                 !strncmp(fsm->path, fsm->ldn, i))
01386             {
01387                 *te = '/';
01388                 /* Move pre-existing path marker forward. */
01389                 fsm->dnlx[dc] = (te - dn);
01390                 /*@innercontinue@*/ continue;
01391             }
01392             /*@=usedef =compdef =nullpass =nullderef@*/
01393 
01394             /* Validate next component of path. */
01395             rc = fsmUNSAFE(fsm, FSM_LSTAT);
01396             *te = '/';
01397 
01398             /* Directory already exists? */
01399             if (rc == 0 && S_ISDIR(ost->st_mode)) {
01400                 /* Move pre-existing path marker forward. */
01401                 fsm->dnlx[dc] = (te - dn);
01402             } else if (rc == CPIOERR_ENOENT) {
01403                 rpmfi fi = fsmGetFi(fsm);
01404                 *te = '\0';
01405                 st->st_mode = S_IFDIR | (fi->dperms & 07777);
01406                 rc = fsmNext(fsm, FSM_MKDIR);
01407                 if (!rc) {
01408                     /* XXX FIXME? only new dir will have context set. */
01409                     /* Get file security context from patterns. */
01410                     if (sx != NULL) {
01411                         fsm->fcontext = rpmsxFContext(sx, fsm->path, st->st_mode);
01412                         rc = fsmNext(fsm, FSM_LSETFCON);
01413                     }
01414                     if (fsm->fcontext == NULL)
01415                         rpmMessage(RPMMESS_DEBUG,
01416                             _("%s directory created with perms %04o, no context.\n"),
01417                             fsm->path, (unsigned)(st->st_mode & 07777));
01418                     else
01419                         rpmMessage(RPMMESS_DEBUG,
01420                             _("%s directory created with perms %04o, context %s.\n"),
01421                             fsm->path, (unsigned)(st->st_mode & 07777),
01422                             fsm->fcontext);
01423                     fsm->fcontext = NULL;
01424                 }
01425                 *te = '/';
01426             }
01427             if (rc)
01428                 /*@innerbreak@*/ break;
01429         }
01430         if (rc) break;
01431 
01432         /* Save last validated path. */
01433 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01434         if (fsm->ldnalloc < (dnlen + 1)) {
01435             fsm->ldnalloc = dnlen + 100;
01436             fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
01437         }
01438         if (fsm->ldn != NULL) { /* XXX can't happen */
01439             strcpy(fsm->ldn, fsm->path);
01440             fsm->ldnlen = dnlen;
01441         }
01442 /*@=compdef@*/
01443     }
01444 /*@=boundswrite@*/
01445     dnli = dnlFreeIterator(dnli);
01446     sx = rpmsxFree(sx);
01447     /*@=observertrans =dependenttrans@*/
01448 
01449     fsm->path = path;
01450     st->st_mode = st_mode;              /* XXX restore st->st_mode */
01451 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01452     return rc;
01453 /*@=compdef@*/
01454 }
01455 
01456 #ifdef  NOTYET
01457 
01462 static int fsmStat(/*@special@*/ /*@partial@*/ FSM_t fsm)
01463         /*@globals fileSystem, internalState @*/
01464         /*@modifies fsm, fileSystem, internalState @*/
01465 {
01466     int rc = 0;
01467 
01468     if (fsm->path != NULL) {
01469         int saveernno = errno;
01470         rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
01471                         ? FSM_LSTAT : FSM_STAT));
01472         if (rc == CPIOERR_ENOENT) {
01473             errno = saveerrno;
01474             rc = 0;
01475             fsm->exists = 0;
01476         } else if (rc == 0) {
01477             fsm->exists = 1;
01478         }
01479     } else {
01480         /* Skip %ghost files on build. */
01481         fsm->exists = 0;
01482     }
01483     return rc;
01484 }
01485 #endif
01486 
01487 #define IS_DEV_LOG(_x)  \
01488         ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
01489         !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \
01490         ((_x)[sizeof("/dev/log")-1] == '\0' || \
01491          (_x)[sizeof("/dev/log")-1] == ';'))
01492 
01493 /*@-boundsread@*/
01494 /*@-compmempass@*/
01495 int fsmStage(FSM_t fsm, fileStage stage)
01496 {
01497 #ifdef  UNUSED
01498     fileStage prevStage = fsm->stage;
01499     const char * const prev = fileStageString(prevStage);
01500 #endif
01501     const char * const cur = fileStageString(stage);
01502     struct stat * st = &fsm->sb;
01503     struct stat * ost = &fsm->osb;
01504     int saveerrno = errno;
01505     int rc = fsm->rc;
01506     size_t left;
01507     int i;
01508 
01509 #define _fafilter(_a)   \
01510     (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
01511         ? fileActionString(_a) : "")
01512 
01513     if (stage & FSM_DEAD) {
01514         /* do nothing */
01515     } else if (stage & FSM_INTERNAL) {
01516         if (_fsm_debug && !(stage & FSM_SYSCALL))
01517             rpmMessage(RPMMESS_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n",
01518                 cur,
01519                 (unsigned)st->st_mode, (int)st->st_nlink,
01520                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01521                 (fsm->path ? fsm->path : ""),
01522                 _fafilter(fsm->action));
01523     } else {
01524         const char * apath = NULL;
01525         if (fsm->path)
01526             (void) urlPath(fsm->path, &apath);
01527         fsm->stage = stage;
01528         if (_fsm_debug || !(stage & FSM_VERBOSE))
01529             rpmMessage(RPMMESS_DEBUG, "%-8s  %06o%3d (%4d,%4d)%12lu %s %s\n",
01530                 cur,
01531                 (unsigned)st->st_mode, (int)st->st_nlink,
01532                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01533                 (fsm->path ? apath + fsm->astriplen : ""),
01534                 _fafilter(fsm->action));
01535     }
01536 #undef  _fafilter
01537 
01538     /*@-branchstate@*/
01539     switch (stage) {
01540     case FSM_UNKNOWN:
01541         break;
01542     case FSM_PKGINSTALL:
01543         while (1) {
01544             /* Clean fsm, free'ing memory. Read next archive header. */
01545             rc = fsmUNSAFE(fsm, FSM_INIT);
01546 
01547             /* Exit on end-of-payload. */
01548             if (rc == CPIOERR_HDR_TRAILER) {
01549                 rc = 0;
01550                 /*@loopbreak@*/ break;
01551             }
01552 
01553             /* Exit on error. */
01554             if (rc) {
01555                 fsm->postpone = 1;
01556                 (void) fsmNext(fsm, FSM_UNDO);
01557                 /*@loopbreak@*/ break;
01558             }
01559 
01560             /* Extract file from archive. */
01561             rc = fsmNext(fsm, FSM_PROCESS);
01562             if (rc) {
01563                 (void) fsmNext(fsm, FSM_UNDO);
01564                 /*@loopbreak@*/ break;
01565             }
01566 
01567             /* Notify on success. */
01568             (void) fsmNext(fsm, FSM_NOTIFY);
01569 
01570             rc = fsmNext(fsm, FSM_FINI);
01571             if (rc) {
01572                 /*@loopbreak@*/ break;
01573             }
01574         }
01575         break;
01576     case FSM_PKGERASE:
01577     case FSM_PKGCOMMIT:
01578         while (1) {
01579             /* Clean fsm, free'ing memory. */
01580             rc = fsmUNSAFE(fsm, FSM_INIT);
01581 
01582             /* Exit on end-of-payload. */
01583             if (rc == CPIOERR_HDR_TRAILER) {
01584                 rc = 0;
01585                 /*@loopbreak@*/ break;
01586             }
01587 
01588             /* Rename/erase next item. */
01589             if (fsmNext(fsm, FSM_FINI))
01590                 /*@loopbreak@*/ break;
01591         }
01592         break;
01593     case FSM_PKGBUILD:
01594         while (1) {
01595 
01596             rc = fsmUNSAFE(fsm, FSM_INIT);
01597 
01598             /* Exit on end-of-payload. */
01599             if (rc == CPIOERR_HDR_TRAILER) {
01600                 rc = 0;
01601                 /*@loopbreak@*/ break;
01602             }
01603 
01604             /* Exit on error. */
01605             if (rc) {
01606                 fsm->postpone = 1;
01607                 (void) fsmNext(fsm, FSM_UNDO);
01608                 /*@loopbreak@*/ break;
01609             }
01610 
01611             /* Copy file into archive. */
01612             rc = fsmNext(fsm, FSM_PROCESS);
01613             if (rc) {
01614                 (void) fsmNext(fsm, FSM_UNDO);
01615                 /*@loopbreak@*/ break;
01616             }
01617 
01618             /* Notify on success. */
01619             (void) fsmNext(fsm, FSM_NOTIFY);
01620 
01621             if (fsmNext(fsm, FSM_FINI))
01622                 /*@loopbreak@*/ break;
01623         }
01624 
01625         /* Flush partial sets of hard linked files. */
01626         if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) {
01627             int nlink, j;
01628             while ((fsm->li = fsm->links) != NULL) {
01629                 fsm->links = fsm->li->next;
01630                 fsm->li->next = NULL;
01631 
01632                 /* Re-calculate link count for archive header. */
01633                 for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) {
01634                     if (fsm->li->filex[i] < 0)
01635                         /*@innercontinue@*/ continue;
01636                     nlink++;
01637                     if (j == -1) j = i;
01638                 }
01639                 /* XXX force the contents out as well. */
01640 /*@-boundswrite@*/
01641                 if (j != 0) {
01642                     fsm->li->filex[0] = fsm->li->filex[j];
01643                     fsm->li->filex[j] = -1;
01644                 }
01645 /*@=boundswrite@*/
01646                 fsm->li->sb.st_nlink = nlink;
01647 
01648                 fsm->sb = fsm->li->sb;  /* structure assignment */
01649                 fsm->osb = fsm->sb;     /* structure assignment */
01650 
01651                 if (!rc) rc = writeLinkedFile(fsm);
01652 
01653                 fsm->li = freeHardLink(fsm->li);
01654             }
01655         }
01656 
01657         if (!rc)
01658             rc = fsmNext(fsm, FSM_TRAILER);
01659 
01660         break;
01661     case FSM_CREATE:
01662         {   rpmts ts = fsmGetTs(fsm);
01663 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
01664             fsm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) &&
01665                         fsm->goal != FSM_PKGCOMMIT) ? 0 : 1);
01666 #undef _tsmask
01667         }
01668         fsm->path = _free(fsm->path);
01669         fsm->lpath = _free(fsm->lpath);
01670         fsm->opath = _free(fsm->opath);
01671         fsm->dnlx = _free(fsm->dnlx);
01672 
01673         fsm->ldn = _free(fsm->ldn);
01674         fsm->ldnalloc = fsm->ldnlen = 0;
01675 
01676         fsm->rdsize = fsm->wrsize = 0;
01677         fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
01678         fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
01679         if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
01680             fsm->rdsize = 8 * BUFSIZ;
01681             fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
01682             fsm->wrsize = 8 * BUFSIZ;
01683             fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
01684         }
01685 
01686         fsm->mkdirsdone = 0;
01687         fsm->ix = -1;
01688         fsm->links = NULL;
01689         fsm->li = NULL;
01690         errno = 0;      /* XXX get rid of EBADF */
01691 
01692         /* Detect and create directories not explicitly in package. */
01693         if (fsm->goal == FSM_PKGINSTALL) {
01694 /*@-compdef@*/
01695             rc = fsmNext(fsm, FSM_MKDIRS);
01696 /*@=compdef@*/
01697             if (!rc) fsm->mkdirsdone = 1;
01698         }
01699 
01700         break;
01701     case FSM_INIT:
01702         fsm->path = _free(fsm->path);
01703         fsm->lpath = _free(fsm->lpath);
01704         fsm->postpone = 0;
01705         fsm->diskchecked = fsm->exists = 0;
01706         fsm->subdir = NULL;
01707         fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
01708         fsm->action = FA_UNKNOWN;
01709         fsm->osuffix = NULL;
01710         fsm->nsuffix = NULL;
01711 
01712         if (fsm->goal == FSM_PKGINSTALL) {
01713             /* Read next header from payload, checking for end-of-payload. */
01714             rc = fsmUNSAFE(fsm, FSM_NEXT);
01715         }
01716         if (rc) break;
01717 
01718         /* Identify mapping index. */
01719         fsm->ix = ((fsm->goal == FSM_PKGINSTALL)
01720                 ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
01721 
01722 if (!(fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_LIST)) {
01723         /* Detect end-of-loop and/or mapping error. */
01724 if (!(fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_EXTRACT)) {
01725         if (fsm->ix < 0) {
01726             if (fsm->goal == FSM_PKGINSTALL) {
01727 #if 0
01728                 rpmMessage(RPMMESS_WARNING,
01729                     _("archive file %s was not found in header file list\n"),
01730                         fsm->path);
01731 #endif
01732 /*@-boundswrite@*/
01733                 if (fsm->failedFile && *fsm->failedFile == NULL)
01734                     *fsm->failedFile = xstrdup(fsm->path);
01735 /*@=boundswrite@*/
01736                 rc = CPIOERR_UNMAPPED_FILE;
01737             } else {
01738                 rc = CPIOERR_HDR_TRAILER;
01739             }
01740             break;
01741         }
01742 }
01743 
01744         /* On non-install, mode must be known so that dirs don't get suffix. */
01745         if (fsm->goal != FSM_PKGINSTALL) {
01746             rpmfi fi = fsmGetFi(fsm);
01747             st->st_mode = fi->fmodes[fsm->ix];
01748         }
01749 }
01750 
01751         /* Generate file path. */
01752         rc = fsmNext(fsm, FSM_MAP);
01753         if (rc) break;
01754 
01755         /* Perform lstat/stat for disk file. */
01756 #ifdef  NOTYET
01757         rc = fsmStat(fsm);
01758 #else
01759         if (fsm->path != NULL &&
01760             !(fsm->goal == FSM_PKGINSTALL && S_ISREG(st->st_mode)))
01761         {
01762             rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
01763                         ? FSM_LSTAT : FSM_STAT));
01764             if (rc == CPIOERR_ENOENT) {
01765                 errno = saveerrno;
01766                 rc = 0;
01767                 fsm->exists = 0;
01768             } else if (rc == 0) {
01769                 fsm->exists = 1;
01770             }
01771         } else {
01772             /* Skip %ghost files on build. */
01773             fsm->exists = 0;
01774         }
01775 #endif
01776         fsm->diskchecked = 1;
01777         if (rc) break;
01778 
01779         /* On non-install, the disk file stat is what's remapped. */
01780 /*@-boundswrite@*/
01781         if (fsm->goal != FSM_PKGINSTALL)
01782             *st = *ost;                 /* structure assignment */
01783 /*@=boundswrite@*/
01784 
01785         /* Remap file perms, owner, and group. */
01786         rc = fsmMapAttrs(fsm);
01787         if (rc) break;
01788 
01789         fsm->postpone = XFA_SKIPPING(fsm->action);
01790         if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
01791             /*@-evalorder@*/ /* FIX: saveHardLink can modify fsm */
01792             if (!(S_ISDIR(st->st_mode) || S_ISLNK(st->st_mode))
01793              && (st->st_nlink > 1 || fsm->lpath != NULL))
01794                 fsm->postpone = saveHardLink(fsm);
01795             /*@=evalorder@*/
01796         }
01797 if (fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_LIST) fsm->postpone = 1;
01798         break;
01799     case FSM_PRE:
01800         break;
01801     case FSM_MAP:
01802         rc = fsmMapPath(fsm);
01803         break;
01804     case FSM_MKDIRS:
01805         rc = fsmMkdirs(fsm);
01806         break;
01807     case FSM_RMDIRS:
01808         if (fsm->dnlx)
01809             rc = fsmRmdirs(fsm);
01810         break;
01811     case FSM_PROCESS:
01812         if (fsm->postpone) {
01813             if (fsm->goal == FSM_PKGINSTALL) {
01814                 /* XXX Skip over file body, archive headers already done. */
01815                 if (S_ISREG(st->st_mode))
01816                     rc = fsmNext(fsm, FSM_EAT);
01817             }
01818             break;
01819         }
01820 
01821         if (fsm->goal == FSM_PKGBUILD) {
01822             if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
01823                 break;
01824             if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
01825                 struct hardLink_s * li, * prev;
01826 
01827 if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) break;
01828                 rc = writeLinkedFile(fsm);
01829                 if (rc) break;  /* W2DO? */
01830 
01831                 for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
01832                      if (li == fsm->li)
01833                         /*@loopbreak@*/ break;
01834 
01835                 if (prev == NULL)
01836                     fsm->links = fsm->li->next;
01837                 else
01838                     prev->next = fsm->li->next;
01839                 fsm->li->next = NULL;
01840                 fsm->li = freeHardLink(fsm->li);
01841             } else {
01842                 rc = writeFile(fsm, 1);
01843             }
01844             break;
01845         }
01846 
01847         if (fsm->goal != FSM_PKGINSTALL)
01848             break;
01849 
01850         if (S_ISREG(st->st_mode) && fsm->lpath != NULL) {
01851             const char * opath = fsm->opath;
01852             char * t = xmalloc(strlen(fsm->lpath+1) + strlen(fsm->suffix) + 1);
01853             (void) stpcpy(t, fsm->lpath+1);
01854              fsm->opath = t;
01855             /* XXX link(fsm->opath, fsm->path) */
01856             rc = fsmNext(fsm, FSM_LINK);
01857             if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01858 /*@-boundswrite@*/
01859                 *fsm->failedFile = xstrdup(fsm->path);
01860 /*@=boundswrite@*/
01861             }
01862             fsm->opath = _free(fsm->opath);
01863             fsm->opath = opath;
01864             break;      /* XXX so that delayed hard links get skipped. */
01865         }
01866         if (S_ISREG(st->st_mode)) {
01867             const char * path = fsm->path;
01868             if (fsm->osuffix)
01869                 fsm->path = fsmFsPath(fsm, st, NULL, NULL);
01870             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01871 
01872             if (rc == 0 && fsm->osuffix) {
01873                 const char * opath = fsm->opath;
01874                 fsm->opath = fsm->path;
01875                 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
01876                 rc = fsmNext(fsm, FSM_RENAME);
01877                 if (!rc)
01878                     rpmMessage(RPMMESS_WARNING,
01879                         _("%s saved as %s\n"),
01880                                 (fsm->opath ? fsm->opath : ""),
01881                                 (fsm->path ? fsm->path : ""));
01882                 fsm->path = _free(fsm->path);
01883                 fsm->opath = opath;
01884             }
01885 
01886             /*@-dependenttrans@*/
01887             fsm->path = path;
01888             /*@=dependenttrans@*/
01889             if (!(rc == CPIOERR_ENOENT)) return rc;
01890             rc = extractRegular(fsm);
01891         } else if (S_ISDIR(st->st_mode)) {
01892             mode_t st_mode = st->st_mode;
01893             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01894             if (rc == CPIOERR_ENOENT) {
01895                 st->st_mode &= ~07777;          /* XXX abuse st->st_mode */
01896                 st->st_mode |=  00700;
01897                 rc = fsmNext(fsm, FSM_MKDIR);
01898                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
01899             }
01900         } else if (S_ISLNK(st->st_mode)) {
01901 assert(fsm->lpath != NULL);
01902             /*@=dependenttrans@*/
01903             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01904             if (rc == CPIOERR_ENOENT)
01905                 rc = fsmNext(fsm, FSM_SYMLINK);
01906         } else if (S_ISFIFO(st->st_mode)) {
01907             mode_t st_mode = st->st_mode;
01908             /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
01909             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01910             if (rc == CPIOERR_ENOENT) {
01911                 st->st_mode = 0000;             /* XXX abuse st->st_mode */
01912                 rc = fsmNext(fsm, FSM_MKFIFO);
01913                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
01914             }
01915         } else if (S_ISCHR(st->st_mode) ||
01916                    S_ISBLK(st->st_mode) ||
01917     /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
01918         {
01919             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01920             if (rc == CPIOERR_ENOENT)
01921                 rc = fsmNext(fsm, FSM_MKNOD);
01922         } else {
01923             /* XXX Repackaged payloads may be missing files. */
01924             if (fsm->repackaged)
01925                 break;
01926 
01927             /* XXX Special case /dev/log, which shouldn't be packaged anyways */
01928             if (!IS_DEV_LOG(fsm->path))
01929                 rc = CPIOERR_UNKNOWN_FILETYPE;
01930         }
01931         if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
01932             fsm->li->createdPath = fsm->li->linkIndex;
01933             rc = fsmMakeLinks(fsm);
01934         }
01935         break;
01936     case FSM_POST:
01937         break;
01938     case FSM_MKLINKS:
01939         rc = fsmMakeLinks(fsm);
01940         break;
01941     case FSM_NOTIFY:            /* XXX move from fsm to psm -> tsm */
01942         if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
01943             rpmts ts = fsmGetTs(fsm);
01944             rpmfi fi = fsmGetFi(fsm);
01945             void * ptr;
01946             unsigned long long archivePos = fdGetCpioPos(fsm->cfd);
01947             if (archivePos > fi->archivePos) {
01948                 fi->archivePos = archivePos;
01949                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS,
01950                         fi->archivePos, fi->archiveSize);
01951             }
01952         }
01953         break;
01954     case FSM_UNDO:
01955         if (fsm->postpone)
01956             break;
01957         if (fsm->goal == FSM_PKGINSTALL) {
01958             /* XXX only erase if temp fn w suffix is in use */
01959             if (fsm->sufbuf[0] != '\0')
01960                 (void) fsmNext(fsm,
01961                     (S_ISDIR(st->st_mode) ? FSM_RMDIR : FSM_UNLINK));
01962 
01963 #ifdef  NOTYET  /* XXX remove only dirs just created, not all. */
01964             if (fsm->dnlx)
01965                 (void) fsmNext(fsm, FSM_RMDIRS);
01966 #endif
01967             errno = saveerrno;
01968         }
01969 /*@-boundswrite@*/
01970         if (fsm->failedFile && *fsm->failedFile == NULL)
01971             *fsm->failedFile = xstrdup(fsm->path);
01972 /*@=boundswrite@*/
01973         break;
01974     case FSM_FINI:
01975         if (!fsm->postpone && fsm->commit) {
01976             if (fsm->goal == FSM_PKGINSTALL)
01977                 rc = ((!S_ISDIR(st->st_mode) && st->st_nlink > 1)
01978                         ? fsmCommitLinks(fsm) : fsmNext(fsm, FSM_COMMIT));
01979             if (fsm->goal == FSM_PKGCOMMIT)
01980                 rc = fsmNext(fsm, FSM_COMMIT);
01981             if (fsm->goal == FSM_PKGERASE)
01982                 rc = fsmNext(fsm, FSM_COMMIT);
01983         }
01984         fsm->path = _free(fsm->path);
01985         fsm->lpath = _free(fsm->lpath);
01986         fsm->opath = _free(fsm->opath);
01987 /*@-boundswrite@*/
01988         memset(st, 0, sizeof(*st));
01989         memset(ost, 0, sizeof(*ost));
01990 /*@=boundswrite@*/
01991         break;
01992     case FSM_COMMIT:
01993         /* Rename pre-existing modified or unmanaged file. */
01994         if (fsm->osuffix && fsm->diskchecked &&
01995           (fsm->exists || (fsm->goal == FSM_PKGINSTALL && S_ISREG(st->st_mode))))
01996         {
01997             const char * opath = fsm->opath;
01998             const char * path = fsm->path;
01999             fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
02000             fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
02001             rc = fsmNext(fsm, FSM_RENAME);
02002             if (!rc) {
02003                 rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"),
02004                                 (fsm->opath ? fsm->opath : ""),
02005                                 (fsm->path ? fsm->path : ""));
02006             }
02007             fsm->path = _free(fsm->path);
02008             fsm->path = path;
02009             fsm->opath = _free(fsm->opath);
02010             fsm->opath = opath;
02011         }
02012 
02013         /* Remove erased files. */
02014         if (fsm->goal == FSM_PKGERASE) {
02015             if (fsm->action == FA_ERASE) {
02016                 rpmfi fi = fsmGetFi(fsm);
02017                 if (S_ISDIR(st->st_mode)) {
02018                     rc = fsmNext(fsm, FSM_RMDIR);
02019                     if (!rc) break;
02020                     switch (rc) {
02021                     case CPIOERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
02022                     case CPIOERR_ENOTEMPTY:
02023         /* XXX make sure that build side permits %missingok on directories. */
02024                         if (fsm->fflags & RPMFILE_MISSINGOK)
02025                             /*@innerbreak@*/ break;
02026 
02027                         /* XXX common error message. */
02028                         rpmError(
02029                             (strict_erasures ? RPMERR_RMDIR : RPMDEBUG_RMDIR),
02030                             _("%s rmdir of %s failed: Directory not empty\n"), 
02031                                 rpmfiTypeString(fi), fsm->path);
02032                         /*@innerbreak@*/ break;
02033                     default:
02034                         rpmError(
02035                             (strict_erasures ? RPMERR_RMDIR : RPMDEBUG_RMDIR),
02036                                 _("%s rmdir of %s failed: %s\n"),
02037                                 rpmfiTypeString(fi), fsm->path, strerror(errno));
02038                         /*@innerbreak@*/ break;
02039                     }
02040                 } else {
02041                     rc = fsmNext(fsm, FSM_UNLINK);
02042                     if (!rc) break;
02043                     switch (rc) {
02044                     case CPIOERR_ENOENT:
02045                         if (fsm->fflags & RPMFILE_MISSINGOK)
02046                             /*@innerbreak@*/ break;
02047                         /*@fallthrough@*/
02048                     default:
02049                         rpmError(
02050                             (strict_erasures ? RPMERR_UNLINK : RPMDEBUG_UNLINK),
02051                                 _(" %s: unlink of %s failed: %s\n"),
02052                                 rpmfiTypeString(fi), fsm->path, strerror(errno));
02053                         /*@innerbreak@*/ break;
02054                     }
02055                 }
02056             }
02057             /* XXX Failure to remove is not (yet) cause for failure. */
02058             if (!strict_erasures) rc = 0;
02059             break;
02060         }
02061 
02062         /* XXX Special case /dev/log, which shouldn't be packaged anyways */
02063 if (!(fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_EXTRACT)) {
02064         if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
02065             /* Rename temporary to final file name. */
02066             if (!S_ISDIR(st->st_mode) &&
02067                 (fsm->subdir || fsm->suffix || fsm->nsuffix))
02068             {
02069                 fsm->opath = fsm->path;
02070                 fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
02071                 rc = fsmNext(fsm, FSM_RENAME);
02072                 if (rc)
02073                         (void) Unlink(fsm->opath);
02074                 else if (fsm->nsuffix) {
02075                     const char * opath = fsmFsPath(fsm, st, NULL, NULL);
02076                     rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"),
02077                                 (opath ? opath : ""),
02078                                 (fsm->path ? fsm->path : ""));
02079                     opath = _free(opath);
02080                 }
02081                 fsm->opath = _free(fsm->opath);
02082             }
02083             /*
02084              * Set file security context (if not disabled).
02085              */
02086             if (!rc && !getuid()) {
02087                 rc = fsmMapFContext(fsm);
02088                 if (!rc)
02089                     rc = fsmNext(fsm, FSM_LSETFCON);
02090                 fsm->fcontext = NULL;
02091             }
02092             if (S_ISLNK(st->st_mode)) {
02093                 if (!rc && !getuid())
02094                     rc = fsmNext(fsm, FSM_LCHOWN);
02095             } else {
02096                 if (!rc && !getuid())
02097                     rc = fsmNext(fsm, FSM_CHOWN);
02098                 if (!rc)
02099                     rc = fsmNext(fsm, FSM_CHMOD);
02100                 if (!rc) {
02101                     time_t mtime = st->st_mtime;
02102                     rpmfi fi = fsmGetFi(fsm);
02103                     if (fi->fmtimes)
02104                         st->st_mtime = fi->fmtimes[fsm->ix];
02105                     rc = fsmNext(fsm, FSM_UTIME);
02106                     st->st_mtime = mtime;
02107                 }
02108             }
02109         }
02110 }
02111 
02112         /* Notify on success. */
02113         if (!rc)                rc = fsmNext(fsm, FSM_NOTIFY);
02114         else if (fsm->failedFile && *fsm->failedFile == NULL) {
02115 /*@-boundswrite@*/
02116             *fsm->failedFile = fsm->path;
02117 /*@=boundswrite@*/
02118             fsm->path = NULL;
02119         }
02120         break;
02121     case FSM_DESTROY:
02122         fsm->path = _free(fsm->path);
02123 
02124         /* Check for hard links missing from payload. */
02125         while ((fsm->li = fsm->links) != NULL) {
02126             fsm->links = fsm->li->next;
02127             fsm->li->next = NULL;
02128             if (fsm->goal == FSM_PKGINSTALL &&
02129                         fsm->commit && fsm->li->linksLeft)
02130             {
02131                 for (i = 0 ; i < fsm->li->linksLeft; i++) {
02132                     if (fsm->li->filex[i] < 0)
02133                         /*@innercontinue@*/ continue;
02134                     rc = CPIOERR_MISSING_HARDLINK;
02135                     if (fsm->failedFile && *fsm->failedFile == NULL) {
02136                         fsm->ix = fsm->li->filex[i];
02137                         if (!fsmNext(fsm, FSM_MAP)) {
02138 /*@-boundswrite@*/
02139                             *fsm->failedFile = fsm->path;
02140 /*@=boundswrite@*/
02141                             fsm->path = NULL;
02142                         }
02143                     }
02144                     /*@loopbreak@*/ break;
02145                 }
02146             }
02147             if (fsm->goal == FSM_PKGBUILD &&
02148                 (fsm->mapFlags & CPIO_ALL_HARDLINKS))
02149             {
02150                 rc = CPIOERR_MISSING_HARDLINK;
02151             }
02152             fsm->li = freeHardLink(fsm->li);
02153         }
02154         fsm->ldn = _free(fsm->ldn);
02155         fsm->ldnalloc = fsm->ldnlen = 0;
02156         fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
02157         fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
02158         break;
02159     case FSM_VERIFY:
02160         if (fsm->diskchecked && !fsm->exists) {
02161             rc = CPIOERR_ENOENT;
02162             break;
02163         }
02164         if (S_ISREG(st->st_mode)) {
02165             char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
02166 /*@-boundswrite@*/
02167             (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
02168 /*@=boundswrite@*/
02169             /*
02170              * XXX HP-UX (and other os'es) don't permit unlink on busy
02171              * XXX files.
02172              */
02173             fsm->opath = fsm->path;
02174             fsm->path = path;
02175             rc = fsmNext(fsm, FSM_RENAME);
02176             if (!rc)
02177                     (void) fsmNext(fsm, FSM_UNLINK);
02178             else
02179                     rc = CPIOERR_UNLINK_FAILED;
02180             fsm->path = fsm->opath;
02181             fsm->opath = NULL;
02182             return (rc ? rc : CPIOERR_ENOENT);  /* XXX HACK */
02183             /*@notreached@*/ break;
02184         } else if (S_ISDIR(st->st_mode)) {
02185             if (S_ISDIR(ost->st_mode))          return 0;
02186             if (S_ISLNK(ost->st_mode)) {
02187                 rc = fsmUNSAFE(fsm, FSM_STAT);
02188                 if (rc == CPIOERR_ENOENT) rc = 0;
02189                 if (rc) break;
02190                 errno = saveerrno;
02191                 if (S_ISDIR(ost->st_mode))      return 0;
02192             }
02193         } else if (S_ISLNK(st->st_mode)) {
02194             if (S_ISLNK(ost->st_mode)) {
02195         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
02196                 rc = fsmUNSAFE(fsm, FSM_READLINK);
02197                 errno = saveerrno;
02198                 if (rc) break;
02199                 if (!strcmp(fsm->lpath, fsm->rdbuf))    return 0;
02200             }
02201         } else if (S_ISFIFO(st->st_mode)) {
02202             if (S_ISFIFO(ost->st_mode))         return 0;
02203         } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
02204             if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
02205                 (ost->st_rdev == st->st_rdev))  return 0;
02206         } else if (S_ISSOCK(st->st_mode)) {
02207             if (S_ISSOCK(ost->st_mode))         return 0;
02208         }
02209             /* XXX shouldn't do this with commit/undo. */
02210         rc = 0;
02211         if (fsm->stage == FSM_PROCESS) rc = fsmNext(fsm, FSM_UNLINK);
02212         if (rc == 0)    rc = CPIOERR_ENOENT;
02213         return (rc ? rc : CPIOERR_ENOENT);      /* XXX HACK */
02214         /*@notreached@*/ break;
02215 
02216     case FSM_UNLINK:
02217         /* XXX Remove setuid/setgid bits on possibly hard linked files. */
02218         if (fsm->mapFlags & CPIO_SBIT_CHECK) {
02219             struct stat stb;
02220             if (Lstat(fsm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
02221                 /* XXX rc = fsmNext(fsm, FSM_CHMOD); instead */
02222                 int xx = chmod(fsm->path, stb.st_mode & 0777);
02223             }
02224         }
02225         rc = Unlink(fsm->path);
02226         if (_fsm_debug && (stage & FSM_SYSCALL))
02227             rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
02228                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02229         if (rc < 0)
02230             rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_UNLINK_FAILED);
02231         break;
02232     case FSM_RENAME:
02233         /* XXX Remove setuid/setgid bits on possibly hard linked files. */
02234         if (fsm->mapFlags & CPIO_SBIT_CHECK) {
02235             struct stat stb;
02236             if (Lstat(fsm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
02237                 /* XXX rc = fsmNext(fsm, FSM_CHMOD); instead */
02238                 int xx = chmod(fsm->path, stb.st_mode & 0777);
02239             }
02240         }
02241         rc = Rename(fsm->opath, fsm->path);
02242         /* XXX Repackaged payloads may be missing files. */
02243         if (fsm->repackaged)
02244             rc = 0;
02245 #if defined(ETXTBSY)
02246         if (rc && errno == ETXTBSY) {
02247             char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
02248             (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
02249             /*
02250              * XXX HP-UX (and other os'es) don't permit rename to busy
02251              * XXX files.
02252              */
02253             rc = Rename(fsm->path, path);
02254             if (!rc) rc = Rename(fsm->opath, fsm->path);
02255         }
02256 #endif
02257         if (_fsm_debug && (stage & FSM_SYSCALL))
02258             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02259                 fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
02260         if (rc < 0)     rc = CPIOERR_RENAME_FAILED;
02261         break;
02262     case FSM_MKDIR:
02263         rc = Mkdir(fsm->path, (st->st_mode & 07777));
02264         if (_fsm_debug && (stage & FSM_SYSCALL))
02265             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02266                 fsm->path, (unsigned)(st->st_mode & 07777),
02267                 (rc < 0 ? strerror(errno) : ""));
02268         if (rc < 0)     rc = CPIOERR_MKDIR_FAILED;
02269         break;
02270     case FSM_RMDIR:
02271         rc = Rmdir(fsm->path);
02272         if (_fsm_debug && (stage & FSM_SYSCALL))
02273             rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
02274                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02275         if (rc < 0)
02276             switch (errno) {
02277             case ENOENT:        rc = CPIOERR_ENOENT;    /*@switchbreak@*/ break;
02278             case ENOTEMPTY:     rc = CPIOERR_ENOTEMPTY; /*@switchbreak@*/ break;
02279             default:            rc = CPIOERR_RMDIR_FAILED; /*@switchbreak@*/ break;
02280             }
02281         break;
02282     case FSM_LSETFCON:
02283       { const char * fsmpath = NULL;
02284         if (fsm->fcontext == NULL || *fsm->fcontext == '\0'
02285          || !strcmp(fsm->fcontext, "<<none>>"))
02286             break;
02287         (void) urlPath(fsm->path, &fsmpath);    /* XXX fsm->path */
02288         rc = lsetfilecon(fsmpath, (security_context_t)fsm->fcontext);
02289         if (_fsm_debug && (stage & FSM_SYSCALL))
02290             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02291                 fsm->path, fsm->fcontext,
02292                 (rc < 0 ? strerror(errno) : ""));
02293         if (rc < 0) rc = (errno == EOPNOTSUPP ? 0 : CPIOERR_LSETFCON_FAILED);
02294       } break;
02295     case FSM_CHOWN:
02296         rc = Chown(fsm->path, st->st_uid, st->st_gid);
02297         if (_fsm_debug && (stage & FSM_SYSCALL))
02298             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
02299                 fsm->path, (int)st->st_uid, (int)st->st_gid,
02300                 (rc < 0 ? strerror(errno) : ""));
02301         if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
02302         break;
02303     case FSM_LCHOWN:
02304 #if ! CHOWN_FOLLOWS_SYMLINK
02305         rc = Lchown(fsm->path, st->st_uid, st->st_gid);
02306         if (_fsm_debug && (stage & FSM_SYSCALL))
02307             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
02308                 fsm->path, (int)st->st_uid, (int)st->st_gid,
02309                 (rc < 0 ? strerror(errno) : ""));
02310         if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
02311 #endif
02312         break;
02313     case FSM_CHMOD:
02314         rc = Chmod(fsm->path, (st->st_mode & 07777));
02315         if (_fsm_debug && (stage & FSM_SYSCALL))
02316             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02317                 fsm->path, (unsigned)(st->st_mode & 07777),
02318                 (rc < 0 ? strerror(errno) : ""));
02319         if (rc < 0)     rc = CPIOERR_CHMOD_FAILED;
02320         break;
02321     case FSM_UTIME:
02322         {   struct utimbuf stamp;
02323             stamp.actime = st->st_mtime;
02324             stamp.modtime = st->st_mtime;
02325             rc = Utime(fsm->path, &stamp);
02326             if (_fsm_debug && (stage & FSM_SYSCALL))
02327                 rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
02328                         fsm->path, (unsigned)st->st_mtime,
02329                         (rc < 0 ? strerror(errno) : ""));
02330             if (rc < 0) rc = CPIOERR_UTIME_FAILED;
02331         }
02332         break;
02333     case FSM_SYMLINK:
02334         rc = Symlink(fsm->lpath, fsm->path);
02335         if (_fsm_debug && (stage & FSM_SYSCALL))
02336             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02337                 fsm->lpath, fsm->path, (rc < 0 ? strerror(errno) : ""));
02338         if (rc < 0)     rc = CPIOERR_SYMLINK_FAILED;
02339         break;
02340     case FSM_LINK:
02341         rc = Link(fsm->opath, fsm->path);
02342         if (_fsm_debug && (stage & FSM_SYSCALL))
02343             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02344                 fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
02345         if (rc < 0)     rc = CPIOERR_LINK_FAILED;
02346         break;
02347     case FSM_MKFIFO:
02348         rc = Mkfifo(fsm->path, (st->st_mode & 07777));
02349         if (_fsm_debug && (stage & FSM_SYSCALL))
02350             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02351                 fsm->path, (unsigned)(st->st_mode & 07777),
02352                 (rc < 0 ? strerror(errno) : ""));
02353         if (rc < 0)     rc = CPIOERR_MKFIFO_FAILED;
02354         break;
02355     case FSM_MKNOD:
02356         /*@-unrecog -portability @*/ /* FIX: check S_IFIFO or dev != 0 */
02357         rc = Mknod(fsm->path, (st->st_mode & ~07777), st->st_rdev);
02358         /*@=unrecog =portability @*/
02359         if (_fsm_debug && (stage & FSM_SYSCALL))
02360             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
02361                 fsm->path, (unsigned)(st->st_mode & ~07777),
02362                 (unsigned)st->st_rdev,
02363                 (rc < 0 ? strerror(errno) : ""));
02364         if (rc < 0)     rc = CPIOERR_MKNOD_FAILED;
02365         break;
02366     case FSM_LSTAT:
02367         rc = Lstat(fsm->path, ost);
02368         if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
02369             rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
02370                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02371         if (rc < 0) {
02372             rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_LSTAT_FAILED);
02373             memset(ost, 0, sizeof(*ost));       /* XXX s390x hackery */
02374         }
02375         break;
02376     case FSM_STAT:
02377         rc = Stat(fsm->path, ost);
02378         if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
02379             rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
02380                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02381         if (rc < 0) {
02382             rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_STAT_FAILED);
02383             memset(ost, 0, sizeof(*ost));       /* XXX s390x hackery */
02384         }
02385         break;
02386     case FSM_READLINK:
02387         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
02388 /*@-boundswrite@*/
02389         rc = Readlink(fsm->path, fsm->rdbuf, fsm->rdsize - 1);
02390 /*@=boundswrite@*/
02391         if (_fsm_debug && (stage & FSM_SYSCALL))
02392             rpmMessage(RPMMESS_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
02393                 fsm->path, (int)(fsm->rdsize -1), (rc < 0 ? strerror(errno) : ""));
02394         if (rc < 0)     rc = CPIOERR_READLINK_FAILED;
02395         else {
02396             fsm->rdnb = rc;
02397 /*@-boundswrite@*/
02398             fsm->rdbuf[fsm->rdnb] = '\0';
02399 /*@=boundswrite@*/
02400             rc = 0;
02401         }
02402         break;
02403     case FSM_CHROOT:
02404         break;
02405 
02406     case FSM_NEXT:
02407         rc = fsmUNSAFE(fsm, FSM_HREAD);
02408         if (rc) break;
02409         if (!strcmp(fsm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
02410             fsm->path = _free(fsm->path);
02411             rc = CPIOERR_HDR_TRAILER;
02412         }
02413         if (!rc)
02414             rc = fsmNext(fsm, FSM_POS);
02415         break;
02416     case FSM_EAT:
02417         for (left = st->st_size; left > 0; left -= fsm->rdnb) {
02418             fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
02419             rc = fsmNext(fsm, FSM_DREAD);
02420             if (rc)
02421                 /*@loopbreak@*/ break;
02422         }
02423         break;
02424     case FSM_POS:
02425         left = (fsm->blksize - (fdGetCpioPos(fsm->cfd) % fsm->blksize)) % fsm->blksize;
02426         if (left) {
02427             fsm->wrlen = left;
02428             (void) fsmNext(fsm, FSM_DREAD);
02429         }
02430         break;
02431     case FSM_PAD:
02432         left = (fsm->blksize - (fdGetCpioPos(fsm->cfd) % fsm->blksize)) % fsm->blksize;
02433         if (left) {
02434 /*@-boundswrite@*/
02435             memset(fsm->rdbuf, 0, left);
02436 /*@=boundswrite@*/
02437             /* XXX DWRITE uses rdnb for I/O length. */
02438             fsm->rdnb = left;
02439             (void) fsmNext(fsm, FSM_DWRITE);
02440         }
02441         break;
02442     case FSM_TRAILER:
02443         rc = (*fsm->trailerWrite) (fsm);        /* Write payload trailer. */
02444         break;
02445     case FSM_HREAD:
02446         rc = fsmNext(fsm, FSM_POS);
02447         if (!rc)
02448             rc = (*fsm->headerRead) (fsm, st);  /* Read next payload header. */
02449         break;
02450     case FSM_HWRITE:
02451         rc = (*fsm->headerWrite) (fsm, st);     /* Write next payload header. */
02452         break;
02453     case FSM_DREAD:
02454 /*@-boundswrite@*/
02455         fsm->rdnb = Fread(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->wrlen, fsm->cfd);
02456 /*@=boundswrite@*/
02457         if (_fsm_debug && (stage & FSM_SYSCALL))
02458             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
02459                 cur, (fsm->wrbuf == fsm->wrb ? "wrbuf" : "mmap"),
02460                 (int)fsm->wrlen, (int)fsm->rdnb);
02461         if (fsm->rdnb != fsm->wrlen || Ferror(fsm->cfd))
02462             rc = CPIOERR_READ_FAILED;
02463         if (fsm->rdnb > 0)
02464             fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->rdnb);
02465         break;
02466     case FSM_DWRITE:
02467         fsm->wrnb = Fwrite(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdnb, fsm->cfd);
02468         if (_fsm_debug && (stage & FSM_SYSCALL))
02469             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
02470                 cur, (fsm->rdbuf == fsm->rdb ? "rdbuf" : "mmap"),
02471                 (int)fsm->rdnb, (int)fsm->wrnb);
02472         if (fsm->rdnb != fsm->wrnb || Ferror(fsm->cfd))
02473             rc = CPIOERR_WRITE_FAILED;
02474         if (fsm->wrnb > 0)
02475             fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->wrnb);
02476         break;
02477 
02478     case FSM_ROPEN:
02479         fsm->rfd = Fopen(fsm->path, "r");
02480         if (fsm->rfd == NULL || Ferror(fsm->rfd)) {
02481             if (fsm->rfd != NULL)       (void) fsmNext(fsm, FSM_RCLOSE);
02482             fsm->rfd = NULL;
02483             rc = CPIOERR_OPEN_FAILED;
02484             break;
02485         }
02486         if (_fsm_debug && (stage & FSM_SYSCALL))
02487             rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
02488                 fsm->path, fsm->rfd, fsm->rdbuf);
02489         break;
02490     case FSM_READ:
02491 /*@-boundswrite@*/
02492         fsm->rdnb = Fread(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdlen, fsm->rfd);
02493 /*@=boundswrite@*/
02494         if (_fsm_debug && (stage & FSM_SYSCALL))
02495             rpmMessage(RPMMESS_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
02496                 cur, (int)fsm->rdlen, (int)fsm->rdnb);
02497         if (fsm->rdnb != fsm->rdlen || Ferror(fsm->rfd))
02498             rc = CPIOERR_READ_FAILED;
02499         break;
02500     case FSM_RCLOSE:
02501         if (fsm->rfd != NULL) {
02502             if (_fsm_debug && (stage & FSM_SYSCALL))
02503                 rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->rfd);
02504             (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
02505                         fdstat_op(fsm->rfd, FDSTAT_DIGEST));
02506             (void) Fclose(fsm->rfd);
02507             errno = saveerrno;
02508         }
02509         fsm->rfd = NULL;
02510         break;
02511     case FSM_WOPEN:
02512         fsm->wfd = Fopen(fsm->path, "w");
02513         if (fsm->wfd == NULL || Ferror(fsm->wfd)) {
02514             if (fsm->wfd != NULL)       (void) fsmNext(fsm, FSM_WCLOSE);
02515             fsm->wfd = NULL;
02516             rc = CPIOERR_OPEN_FAILED;
02517         }
02518         if (_fsm_debug && (stage & FSM_SYSCALL))
02519             rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
02520                 fsm->path, fsm->wfd, fsm->wrbuf);
02521         break;
02522     case FSM_WRITE:
02523         fsm->wrnb = Fwrite(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->rdnb, fsm->wfd);
02524         if (_fsm_debug && (stage & FSM_SYSCALL))
02525             rpmMessage(RPMMESS_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
02526                 cur, (int)fsm->rdnb, (int)fsm->wrnb);
02527         if (fsm->rdnb != fsm->wrnb || Ferror(fsm->wfd))
02528             rc = CPIOERR_WRITE_FAILED;
02529         break;
02530     case FSM_WCLOSE:
02531         if (fsm->wfd != NULL) {
02532             if (_fsm_debug && (stage & FSM_SYSCALL))
02533                 rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->wfd);
02534             (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
02535                         fdstat_op(fsm->wfd, FDSTAT_DIGEST));
02536             (void) Fclose(fsm->wfd);
02537             errno = saveerrno;
02538         }
02539         fsm->wfd = NULL;
02540         break;
02541 
02542     default:
02543         break;
02544     }
02545     /*@=branchstate@*/
02546 
02547     if (!(stage & FSM_INTERNAL)) {
02548         fsm->rc = (rc == CPIOERR_HDR_TRAILER ? 0 : rc);
02549     }
02550     return rc;
02551 }
02552 /*@=compmempass@*/
02553 /*@=boundsread@*/
02554 
02555 /*@observer@*/ const char * fileActionString(fileAction a)
02556 {
02557     switch (a) {
02558     case FA_UNKNOWN:    return "unknown";
02559     case FA_CREATE:     return "create";
02560     case FA_COPYOUT:    return "copyout";
02561     case FA_COPYIN:     return "copyin";
02562     case FA_BACKUP:     return "backup";
02563     case FA_SAVE:       return "save";
02564     case FA_SKIP:       return "skip";
02565     case FA_ALTNAME:    return "altname";
02566     case FA_ERASE:      return "erase";
02567     case FA_SKIPNSTATE: return "skipnstate";
02568     case FA_SKIPNETSHARED: return "skipnetshared";
02569     case FA_SKIPCOLOR:  return "skipcolor";
02570     default:            return "???";
02571     }
02572     /*@notreached@*/
02573 }
02574 
02575 /*@observer@*/ const char * fileStageString(fileStage a) {
02576     switch(a) {
02577     case FSM_UNKNOWN:   return "unknown";
02578 
02579     case FSM_PKGINSTALL:return "INSTALL";
02580     case FSM_PKGERASE:  return "ERASE";
02581     case FSM_PKGBUILD:  return "BUILD";
02582     case FSM_PKGCOMMIT: return "COMMIT";
02583     case FSM_PKGUNDO:   return "UNDO";
02584 
02585     case FSM_CREATE:    return "create";
02586     case FSM_INIT:      return "init";
02587     case FSM_MAP:       return "map";
02588     case FSM_MKDIRS:    return "mkdirs";
02589     case FSM_RMDIRS:    return "rmdirs";
02590     case FSM_PRE:       return "pre";
02591     case FSM_PROCESS:   return "process";
02592     case FSM_POST:      return "post";
02593     case FSM_MKLINKS:   return "mklinks";
02594     case FSM_NOTIFY:    return "notify";
02595     case FSM_UNDO:      return "undo";
02596     case FSM_FINI:      return "fini";
02597     case FSM_COMMIT:    return "commit";
02598     case FSM_DESTROY:   return "destroy";
02599     case FSM_VERIFY:    return "verify";
02600 
02601     case FSM_UNLINK:    return "Unlink";
02602     case FSM_RENAME:    return "Rename";
02603     case FSM_MKDIR:     return "Mkdir";
02604     case FSM_RMDIR:     return "rmdir";
02605     case FSM_LSETFCON:  return "lsetfcon";
02606     case FSM_CHOWN:     return "chown";
02607     case FSM_LCHOWN:    return "lchown";
02608     case FSM_CHMOD:     return "chmod";
02609     case FSM_UTIME:     return "utime";
02610     case FSM_SYMLINK:   return "symlink";
02611     case FSM_LINK:      return "Link";
02612     case FSM_MKFIFO:    return "mkfifo";
02613     case FSM_MKNOD:     return "mknod";
02614     case FSM_LSTAT:     return "Lstat";
02615     case FSM_STAT:      return "Stat";
02616     case FSM_READLINK:  return "Readlink";
02617     case FSM_CHROOT:    return "chroot";
02618 
02619     case FSM_NEXT:      return "next";
02620     case FSM_EAT:       return "eat";
02621     case FSM_POS:       return "pos";
02622     case FSM_PAD:       return "pad";
02623     case FSM_TRAILER:   return "trailer";
02624     case FSM_HREAD:     return "hread";
02625     case FSM_HWRITE:    return "hwrite";
02626     case FSM_DREAD:     return "Fread";
02627     case FSM_DWRITE:    return "Fwrite";
02628 
02629     case FSM_ROPEN:     return "Fopen";
02630     case FSM_READ:      return "Fread";
02631     case FSM_RCLOSE:    return "Fclose";
02632     case FSM_WOPEN:     return "Fopen";
02633     case FSM_WRITE:     return "Fwrite";
02634     case FSM_WCLOSE:    return "Fclose";
02635 
02636     default:            return "???";
02637     }
02638     /*@noteached@*/
02639 }

Generated on Wed Feb 6 22:32:28 2008 for rpm by  doxygen 1.5.1