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         D_("========== 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         security_context_t scon = NULL;
00670 
00671         if (matchpathcon(fsm->path, st->st_mode, &scon) == 0 && scon != NULL)
00672             fsm->fcontext = scon;
00673         else {
00674             int i = fsm->ix;
00675 
00676             /* Get file security context from package. */
00677             if (fi && i >= 0 && i < fi->fc)
00678                 fsm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL);
00679         }
00680     }
00681     return 0;
00682 }
00683 
00684 int fsmMapPath(FSM_t fsm)
00685 {
00686     rpmfi fi = fsmGetFi(fsm);   /* XXX const except for fstates */
00687     int rc = 0;
00688     int i;
00689 
00690     fsm->osuffix = NULL;
00691     fsm->nsuffix = NULL;
00692     fsm->astriplen = 0;
00693     fsm->action = FA_UNKNOWN;
00694     fsm->mapFlags = fi->mapflags;
00695 
00696     i = fsm->ix;
00697     if (fi && i >= 0 && i < fi->fc) {
00698 
00699 /*@-boundsread@*/
00700         fsm->astriplen = fi->astriplen;
00701         fsm->action = (fi->actions ? fi->actions[i] : fi->action);
00702         fsm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
00703         fsm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
00704 
00705         /* src rpms have simple base name in payload. */
00706         fsm->dirName = fi->dnl[fi->dil[i]];
00707         fsm->baseName = fi->bnl[i];
00708 /*@=boundsread@*/
00709 
00710 /*@-boundswrite@*/
00711         switch (fsm->action) {
00712         case FA_SKIP:
00713             break;
00714         case FA_UNKNOWN:
00715             break;
00716 
00717         case FA_COPYOUT:
00718             break;
00719         case FA_COPYIN:
00720         case FA_CREATE:
00721 assert(rpmteType(fi->te) == TR_ADDED);
00722             break;
00723 
00724         case FA_SKIPNSTATE:
00725             if (fi->fstates && rpmteType(fi->te) == TR_ADDED)
00726                 fi->fstates[i] = RPMFILE_STATE_NOTINSTALLED;
00727             break;
00728 
00729         case FA_SKIPNETSHARED:
00730             if (fi->fstates && rpmteType(fi->te) == TR_ADDED)
00731                 fi->fstates[i] = RPMFILE_STATE_NETSHARED;
00732             break;
00733 
00734         case FA_SKIPCOLOR:
00735             if (fi->fstates && rpmteType(fi->te) == TR_ADDED)
00736                 fi->fstates[i] = RPMFILE_STATE_WRONGCOLOR;
00737             break;
00738 
00739         case FA_BACKUP:
00740             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00741             switch (rpmteType(fi->te)) {
00742             case TR_ADDED:
00743                 fsm->osuffix = SUFFIX_RPMORIG;
00744                 /*@innerbreak@*/ break;
00745             case TR_REMOVED:
00746                 fsm->osuffix = SUFFIX_RPMSAVE;
00747                 /*@innerbreak@*/ break;
00748             }
00749             break;
00750 
00751         case FA_ALTNAME:
00752 assert(rpmteType(fi->te) == TR_ADDED);
00753             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00754                 fsm->nsuffix = SUFFIX_RPMNEW;
00755             break;
00756 
00757         case FA_SAVE:
00758 assert(rpmteType(fi->te) == TR_ADDED);
00759             if (!(fsm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00760                 fsm->osuffix = SUFFIX_RPMSAVE;
00761             break;
00762         case FA_ERASE:
00763 #if 0   /* XXX is this a genhdlist fix? */
00764             assert(rpmteType(fi->te) == TR_REMOVED);
00765 #endif
00766             /*
00767              * XXX TODO: %ghost probably shouldn't be removed, but that changes
00768              * legacy rpm behavior.
00769              */
00770             break;
00771         default:
00772             break;
00773         }
00774 /*@=boundswrite@*/
00775 
00776         if ((fsm->mapFlags & CPIO_MAP_PATH) || fsm->nsuffix) {
00777             const struct stat * st = &fsm->sb;
00778             fsm->path = _free(fsm->path);
00779             fsm->path = fsmFsPath(fsm, st, fsm->subdir,
00780                 (fsm->suffix ? fsm->suffix : fsm->nsuffix));
00781         }
00782     }
00783     return rc;
00784 }
00785 
00786 int fsmMapAttrs(FSM_t fsm)
00787 {
00788     struct stat * st = &fsm->sb;
00789     rpmfi fi = fsmGetFi(fsm);
00790     int i = fsm->ix;
00791 
00792     if (fi && i >= 0 && i < fi->fc) {
00793         mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
00794         mode_t finalMode = (fi->fmodes ? fi->fmodes[i] : perms);
00795         dev_t finalRdev = (fi->frdevs ? fi->frdevs[i] : 0);
00796         int_32 finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
00797         uid_t uid = fi->uid;
00798         gid_t gid = fi->gid;
00799 
00800         if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
00801             if (fsm->goal == FSM_PKGINSTALL)
00802                 rpmMessage(RPMMESS_WARNING,
00803                     _("user %s does not exist - using root\n"), fi->fuser[i]);
00804             uid = 0;
00805             finalMode &= ~S_ISUID;      /* turn off suid bit */
00806         }
00807 
00808         if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
00809             if (fsm->goal == FSM_PKGINSTALL)
00810                 rpmMessage(RPMMESS_WARNING,
00811                     _("group %s does not exist - using root\n"), fi->fgroup[i]);
00812             gid = 0;
00813             finalMode &= ~S_ISGID;      /* turn off sgid bit */
00814         }
00815 
00816         if (fsm->mapFlags & CPIO_MAP_MODE)
00817             st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
00818         if (fsm->mapFlags & CPIO_MAP_TYPE) {
00819             st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
00820             if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00821             && st->st_nlink == 0)
00822                 st->st_nlink = 1;
00823             st->st_rdev = finalRdev;
00824             st->st_mtime = finalMtime;
00825         }
00826         if (fsm->mapFlags & CPIO_MAP_UID)
00827             st->st_uid = uid;
00828         if (fsm->mapFlags & CPIO_MAP_GID)
00829             st->st_gid = gid;
00830 
00831         {   rpmts ts = fsmGetTs(fsm);
00832 
00833             /*
00834              * Set file digest (if not disabled).
00835              */
00836             if (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS)) {
00837                 fsm->fdigestalgo = fi->digestalgo;
00838                 fsm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL);
00839                 fsm->digestlen = fi->digestlen;
00840                 fsm->digest = (fi->digests ? (fi->digests + (fsm->digestlen * i)) : NULL);
00841             } else {
00842                 fsm->fdigestalgo = 0;
00843                 fsm->fdigest = NULL;
00844                 fsm->digestlen = 0;
00845                 fsm->digest = NULL;
00846             }
00847         }
00848 
00849     }
00850     return 0;
00851 }
00852 
00858 /*@-compdef@*/
00859 static int extractRegular(/*@special@*/ FSM_t fsm)
00860         /*@uses fsm->fdigest, fsm->digest, fsm->sb, fsm->wfd  @*/
00861         /*@globals h_errno, fileSystem, internalState @*/
00862         /*@modifies fsm, fileSystem, internalState @*/
00863 {
00864     const struct stat * st = &fsm->sb;
00865     int left = st->st_size;
00866     int rc = 0;
00867 
00868     rc = fsmNext(fsm, FSM_WOPEN);
00869     if (rc)
00870         goto exit;
00871 
00872     if (st->st_size > 0 && (fsm->fdigest != NULL || fsm->digest != NULL))
00873         fdInitDigest(fsm->wfd, fsm->fdigestalgo, 0);
00874 
00875     while (left) {
00876 
00877         fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
00878         rc = fsmNext(fsm, FSM_DREAD);
00879         if (rc)
00880             goto exit;
00881 
00882         rc = fsmNext(fsm, FSM_WRITE);
00883         if (rc)
00884             goto exit;
00885 
00886         left -= fsm->wrnb;
00887 
00888         /* Notify iff progress, completion is done elsewhere */
00889         if (!rc && left)
00890             (void) fsmNext(fsm, FSM_NOTIFY);
00891     }
00892 
00893     if (st->st_size > 0 && (fsm->fdigest || fsm->digest)) {
00894         void * digest = NULL;
00895         int asAscii = (fsm->digest == NULL ? 1 : 0);
00896 
00897         (void) Fflush(fsm->wfd);
00898         fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii);
00899 
00900         if (digest == NULL) {
00901             rc = CPIOERR_DIGEST_MISMATCH;
00902             goto exit;
00903         }
00904 
00905         if (fsm->digest != NULL) {
00906             if (memcmp(digest, fsm->digest, fsm->digestlen))
00907                 rc = CPIOERR_DIGEST_MISMATCH;
00908         } else {
00909             if (strcmp(digest, fsm->fdigest))
00910                 rc = CPIOERR_DIGEST_MISMATCH;
00911         }
00912         digest = _free(digest);
00913     }
00914 
00915 exit:
00916     (void) fsmNext(fsm, FSM_WCLOSE);
00917     return rc;
00918 }
00919 /*@=compdef@*/
00920 
00927 /*@-compdef -compmempass@*/
00928 static int writeFile(/*@special@*/ /*@partial@*/ FSM_t fsm, int writeData)
00929         /*@uses fsm->path, fsm->opath, fsm->sb, fsm->osb, fsm->cfd @*/
00930         /*@globals h_errno, fileSystem, internalState @*/
00931         /*@modifies fsm, fileSystem, internalState @*/
00932 {
00933     const char * path = fsm->path;
00934     const char * opath = fsm->opath;
00935     struct stat * st = &fsm->sb;
00936     struct stat * ost = &fsm->osb;
00937     size_t left;
00938     int xx;
00939     int rc;
00940 
00941     st->st_size = (writeData ? ost->st_size : 0);
00942 
00943     /*@-branchstate@*/
00944     if (S_ISDIR(st->st_mode)) {
00945         st->st_size = 0;
00946     } else if (S_ISLNK(st->st_mode)) {
00947         /*
00948          * While linux puts the size of a symlink in the st_size field,
00949          * I don't think that's a specified standard.
00950          */
00951         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
00952         rc = fsmUNSAFE(fsm, FSM_READLINK);
00953         if (rc) goto exit;
00954         st->st_size = fsm->rdnb;
00955         fsm->lpath = xstrdup(fsm->rdbuf);       /* XXX save readlink return. */
00956     }
00957     /*@=branchstate@*/
00958 
00959     if (fsm->mapFlags & CPIO_MAP_ABSOLUTE) {
00960 /*@-boundswrite@*/
00961         int nb = strlen(fsm->dirName) + strlen(fsm->baseName) + sizeof(".");
00962         char * t = alloca(nb);
00963         *t = '\0';
00964         fsm->path = t;
00965         if (fsm->mapFlags & CPIO_MAP_ADDDOT)
00966             *t++ = '.';
00967         t = stpcpy( stpcpy(t, fsm->dirName), fsm->baseName);
00968 /*@=boundswrite@*/
00969     } else if (fsm->mapFlags & CPIO_MAP_PATH) {
00970         rpmfi fi = fsmGetFi(fsm);
00971         if (fi->apath) {
00972             const char * apath = NULL;
00973             (void) urlPath(fi->apath[fsm->ix], &apath);
00974             fsm->path = apath + fi->striplen;
00975         } else
00976             fsm->path = fi->bnl[fsm->ix];
00977     }
00978 
00979     rc = fsmNext(fsm, FSM_HWRITE);
00980     fsm->path = path;
00981     if (rc) goto exit;
00982 
00983     if (writeData && S_ISREG(st->st_mode)) {
00984 #if HAVE_MMAP
00985         char * rdbuf = NULL;
00986         void * mapped = (void *)-1;
00987         size_t nmapped = 0;
00988         /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
00989         int use_mmap = (st->st_size <= 0x07ffffff);
00990 #endif
00991 
00992         rc = fsmNext(fsm, FSM_ROPEN);
00993         if (rc) goto exit;
00994 
00995         /* XXX unbuffered mmap generates *lots* of fdio debugging */
00996 #if HAVE_MMAP
00997         if (use_mmap) {
00998             mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fsm->rfd), 0);
00999             if (mapped != (void *)-1) {
01000                 rdbuf = fsm->rdbuf;
01001                 fsm->rdbuf = (char *) mapped;
01002                 fsm->rdlen = nmapped = st->st_size;
01003 #if defined(MADV_DONTNEED)
01004                 xx = madvise(mapped, nmapped, MADV_DONTNEED);
01005 #endif
01006             }
01007         }
01008 #endif
01009 
01010         left = st->st_size;
01011 
01012         while (left) {
01013 #if HAVE_MMAP
01014           if (mapped != (void *)-1) {
01015             fsm->rdnb = nmapped;
01016           } else
01017 #endif
01018           {
01019             fsm->rdlen = (left > fsm->rdsize ? fsm->rdsize : left),
01020             rc = fsmNext(fsm, FSM_READ);
01021             if (rc) goto exit;
01022           }
01023 
01024             /* XXX DWRITE uses rdnb for I/O length. */
01025             rc = fsmNext(fsm, FSM_DWRITE);
01026             if (rc) goto exit;
01027 
01028             left -= fsm->wrnb;
01029         }
01030 
01031 #if HAVE_MMAP
01032 /*@-branchstate@*/
01033         if (mapped != (void *)-1) {
01034             xx = msync(mapped, nmapped, MS_ASYNC);
01035 #if defined(MADV_DONTNEED)
01036             xx = madvise(mapped, nmapped, MADV_DONTNEED);
01037 #endif
01038 /*@-noeffect@*/
01039             xx = munmap(mapped, nmapped);
01040 /*@=noeffect@*/
01041             fsm->rdbuf = rdbuf;
01042         } else
01043 /*@=branchstate@*/
01044 #endif
01045             xx = fsync(Fileno(fsm->rfd));
01046     }
01047 
01048     rc = fsmNext(fsm, FSM_PAD);
01049     if (rc) goto exit;
01050 
01051     rc = 0;
01052 
01053 exit:
01054     if (fsm->rfd != NULL)
01055         (void) fsmNext(fsm, FSM_RCLOSE);
01056 /*@-dependenttrans@*/
01057     fsm->opath = opath;
01058     fsm->path = path;
01059 /*@=dependenttrans@*/
01060     return rc;
01061 }
01062 /*@=compdef =compmempass@*/
01063 
01069 static int writeLinkedFile(/*@special@*/ /*@partial@*/ FSM_t fsm)
01070         /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->li, fsm->failedFile @*/
01071         /*@globals h_errno, fileSystem, internalState @*/
01072         /*@modifies fsm, fileSystem, internalState @*/
01073 {
01074     const char * path = fsm->path;
01075     const char * lpath = fsm->lpath;
01076     const char * nsuffix = fsm->nsuffix;
01077     int iterIndex = fsm->ix;
01078     int ec = 0;
01079     int rc;
01080     int i;
01081     const char * linkpath = NULL;
01082     int firstfile = 1;
01083 
01084     fsm->path = NULL;
01085     fsm->lpath = NULL;
01086     fsm->nsuffix = NULL;
01087     fsm->ix = -1;
01088 
01089 /*@-boundswrite@*/
01090 /*@-branchstate@*/
01091     for (i = fsm->li->nlink - 1; i >= 0; i--) {
01092 
01093         if (fsm->li->filex[i] < 0) continue;
01094 
01095         fsm->ix = fsm->li->filex[i];
01096 /*@-compdef@*/
01097         rc = fsmNext(fsm, FSM_MAP);
01098 /*@=compdef@*/
01099 
01100         /* XXX tar and cpio have to do things differently. */
01101         if (fsm->headerWrite == tarHeaderWrite) {
01102             if (firstfile) {
01103                 const char * apath = NULL;
01104                 char *t;
01105                 (void) urlPath(fsm->path, &apath);
01106                 /* Remove the buildroot prefix. */
01107                 t = xmalloc(sizeof(".") + strlen(apath + fsm->astriplen));
01108                 (void) stpcpy( stpcpy(t, "."), apath + fsm->astriplen);
01109                 linkpath = t;
01110                 firstfile = 0;
01111             } else
01112                 fsm->lpath = linkpath;
01113 
01114             /* Write data after first link for tar. */
01115             rc = writeFile(fsm, (fsm->lpath == NULL));
01116         } else {
01117             /* Write data after last link for cpio. */
01118             rc = writeFile(fsm, (i == 0));
01119         }
01120         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01121             ec = rc;
01122             *fsm->failedFile = xstrdup(fsm->path);
01123         }
01124 
01125         fsm->path = _free(fsm->path);
01126         fsm->li->filex[i] = -1;
01127     }
01128 /*@=branchstate@*/
01129 /*@=boundswrite@*/
01130 
01131 /*@-dependenttrans@*/
01132     linkpath = _free(linkpath);
01133 /*@=dependenttrans@*/
01134     fsm->ix = iterIndex;
01135     fsm->nsuffix = nsuffix;
01136     fsm->lpath = lpath;
01137     fsm->path = path;
01138     return ec;
01139 }
01140 
01146 /*@-boundsread@*/
01147 /*@-compdef@*/
01148 static int fsmMakeLinks(/*@special@*/ /*@partial@*/ FSM_t fsm)
01149         /*@uses fsm->path, fsm->opath, fsm->nsuffix, fsm->ix, fsm->li @*/
01150         /*@globals h_errno, fileSystem, internalState @*/
01151         /*@modifies fsm, fileSystem, internalState @*/
01152 {
01153     const char * path = fsm->path;
01154     const char * opath = fsm->opath;
01155     const char * nsuffix = fsm->nsuffix;
01156     int iterIndex = fsm->ix;
01157     int ec = 0;
01158     int rc;
01159     int i;
01160 
01161     fsm->path = NULL;
01162     fsm->opath = NULL;
01163     fsm->nsuffix = NULL;
01164     fsm->ix = -1;
01165 
01166     fsm->ix = fsm->li->filex[fsm->li->createdPath];
01167     rc = fsmNext(fsm, FSM_MAP);
01168     fsm->opath = fsm->path;
01169     fsm->path = NULL;
01170     /*@-branchstate@*/
01171     for (i = 0; i < fsm->li->nlink; i++) {
01172         if (fsm->li->filex[i] < 0) continue;
01173         if (fsm->li->createdPath == i) continue;
01174 
01175         fsm->ix = fsm->li->filex[i];
01176         fsm->path = _free(fsm->path);
01177         rc = fsmNext(fsm, FSM_MAP);
01178         if (XFA_SKIPPING(fsm->action)) continue;
01179 
01180         rc = fsmUNSAFE(fsm, FSM_VERIFY);
01181         if (!rc) continue;
01182         if (!(rc == CPIOERR_ENOENT)) break;
01183 
01184         /* XXX link(fsm->opath, fsm->path) */
01185         rc = fsmNext(fsm, FSM_LINK);
01186         if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01187             ec = rc;
01188 /*@-boundswrite@*/
01189             *fsm->failedFile = xstrdup(fsm->path);
01190 /*@=boundswrite@*/
01191         }
01192 
01193         fsm->li->linksLeft--;
01194     }
01195     /*@=branchstate@*/
01196     fsm->path = _free(fsm->path);
01197     fsm->opath = _free(fsm->opath);
01198 
01199     fsm->ix = iterIndex;
01200     fsm->nsuffix = nsuffix;
01201     fsm->path = path;
01202     fsm->opath = opath;
01203     return ec;
01204 }
01205 /*@=compdef@*/
01206 /*@=boundsread@*/
01207 
01213 /*@-compdef@*/
01214 static int fsmCommitLinks(/*@special@*/ /*@partial@*/ FSM_t fsm)
01215         /*@uses fsm->path, fsm->nsuffix, fsm->ix, fsm->sb,
01216                 fsm->li, fsm->links @*/
01217         /*@globals h_errno, fileSystem, internalState @*/
01218         /*@modifies fsm, fileSystem, internalState @*/
01219 {
01220     const char * path = fsm->path;
01221     const char * nsuffix = fsm->nsuffix;
01222     int iterIndex = fsm->ix;
01223     struct stat * st = &fsm->sb;
01224     int rc = 0;
01225     int i;
01226 
01227     fsm->path = NULL;
01228     fsm->nsuffix = NULL;
01229     fsm->ix = -1;
01230 
01231     /*@-branchstate@*/
01232     for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
01233         if (fsm->li->sb.st_ino == st->st_ino && fsm->li->sb.st_dev == st->st_dev)
01234             break;
01235     }
01236     /*@=branchstate@*/
01237 
01238 /*@-boundswrite@*/
01239     for (i = 0; i < fsm->li->nlink; i++) {
01240         if (fsm->li->filex[i] < 0) continue;
01241         fsm->ix = fsm->li->filex[i];
01242         rc = fsmNext(fsm, FSM_MAP);
01243         if (!XFA_SKIPPING(fsm->action))
01244             rc = fsmNext(fsm, FSM_COMMIT);
01245         fsm->path = _free(fsm->path);
01246         fsm->li->filex[i] = -1;
01247     }
01248 /*@=boundswrite@*/
01249 
01250     fsm->ix = iterIndex;
01251     fsm->nsuffix = nsuffix;
01252     fsm->path = path;
01253     return rc;
01254 }
01255 /*@=compdef@*/
01256 
01262 static int fsmRmdirs(/*@special@*/ /*@partial@*/ FSM_t fsm)
01263         /*@uses fsm->path, fsm->dnlx, fsm->ldn, fsm->rdbuf, fsm->iter @*/
01264         /*@globals h_errno, fileSystem, internalState @*/
01265         /*@modifies fsm, fileSystem, internalState @*/
01266 {
01267     const char * path = fsm->path;
01268     void * dnli = dnlInitIterator(fsm, 1);
01269     char * dn = fsm->rdbuf;
01270     int dc = dnlCount(dnli);
01271     int rc = 0;
01272 
01273     fsm->path = NULL;
01274 /*@-boundswrite@*/
01275     dn[0] = '\0';
01276     /*@-observertrans -dependenttrans@*/
01277     if (fsm->ldn != NULL && fsm->dnlx != NULL)
01278     while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
01279         int dnlen = strlen(fsm->path);
01280         char * te;
01281 
01282         dc = dnlIndex(dnli);
01283         if (fsm->dnlx[dc] < 1 || fsm->dnlx[dc] >= dnlen)
01284             continue;
01285 
01286         /* Copy to avoid const on fsm->path. */
01287         te = stpcpy(dn, fsm->path) - 1;
01288         fsm->path = dn;
01289 
01290         /* Remove generated directories. */
01291         /*@-usereleased@*/ /* LCL: te used after release? */
01292         do {
01293             if (*te == '/') {
01294                 *te = '\0';
01295 /*@-compdef@*/
01296                 rc = fsmNext(fsm, FSM_RMDIR);
01297 /*@=compdef@*/
01298                 *te = '/';
01299             }
01300             if (rc)
01301                 /*@innerbreak@*/ break;
01302             te--;
01303         } while ((te - fsm->path) > fsm->dnlx[dc]);
01304         /*@=usereleased@*/
01305     }
01306 /*@=boundswrite@*/
01307     dnli = dnlFreeIterator(dnli);
01308     /*@=observertrans =dependenttrans@*/
01309 
01310     fsm->path = path;
01311     return rc;
01312 }
01313 
01319 static int fsmMkdirs(/*@special@*/ /*@partial@*/ FSM_t fsm)
01320         /*@uses fsm->path, fsm->sb, fsm->osb, fsm->rdbuf, fsm->iter,
01321                 fsm->ldn, fsm->ldnlen, fsm->ldnalloc @*/
01322         /*@defines fsm->dnlx, fsm->ldn @*/
01323         /*@globals h_errno, fileSystem, internalState @*/
01324         /*@modifies fsm, fileSystem, internalState @*/
01325 {
01326     struct stat * st = &fsm->sb;
01327     struct stat * ost = &fsm->osb;
01328     const char * path = fsm->path;
01329     mode_t st_mode = st->st_mode;
01330     void * dnli = dnlInitIterator(fsm, 0);
01331     char * dn = fsm->rdbuf;
01332     int dc = dnlCount(dnli);
01333     int rc = 0;
01334     int i;
01335 /*@-compdef@*/
01336     rpmts ts = fsmGetTs(fsm);
01337 /*@=compdef@*/
01338     rpmsx sx = NULL;
01339 
01340     /* XXX Set file contexts on non-packaged dirs iff selinux enabled. */
01341     if (ts != NULL && rpmtsSELinuxEnabled(ts) == 1 &&
01342       !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS))
01343         sx = rpmtsREContext(ts);
01344 
01345     fsm->path = NULL;
01346 
01347 /*@-boundswrite@*/
01348     dn[0] = '\0';
01349     fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
01350     /*@-observertrans -dependenttrans@*/
01351     if (fsm->dnlx != NULL)
01352     while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
01353         int dnlen = strlen(fsm->path);
01354         char * te;
01355 
01356         dc = dnlIndex(dnli);
01357         if (dc < 0) continue;
01358         fsm->dnlx[dc] = dnlen;
01359         if (dnlen <= 1)
01360             continue;
01361 
01362         /*@-compdef -nullpass@*/        /* FIX: fsm->ldn not defined ??? */
01363         if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
01364             continue;
01365         /*@=compdef =nullpass@*/
01366 
01367         /* Copy to avoid const on fsm->path. */
01368         (void) stpcpy(dn, fsm->path);
01369         fsm->path = dn;
01370 
01371         /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
01372         (void) urlPath(dn, (const char **)&te);
01373         for (i = 1, te++; *te != '\0'; te++, i++) {
01374             if (*te != '/')
01375                 /*@innercontinue@*/ continue;
01376 
01377             *te = '\0';
01378 
01379             /* Already validated? */
01380             /*@-usedef -compdef -nullpass -nullderef@*/
01381             if (i < fsm->ldnlen &&
01382                 (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
01383                 !strncmp(fsm->path, fsm->ldn, i))
01384             {
01385                 *te = '/';
01386                 /* Move pre-existing path marker forward. */
01387                 fsm->dnlx[dc] = (te - dn);
01388                 /*@innercontinue@*/ continue;
01389             }
01390             /*@=usedef =compdef =nullpass =nullderef@*/
01391 
01392             /* Validate next component of path. */
01393             rc = fsmUNSAFE(fsm, FSM_LSTAT);
01394             *te = '/';
01395 
01396             /* Directory already exists? */
01397             if (rc == 0 && S_ISDIR(ost->st_mode)) {
01398                 /* Move pre-existing path marker forward. */
01399                 fsm->dnlx[dc] = (te - dn);
01400             } else if (rc == CPIOERR_ENOENT) {
01401                 rpmfi fi = fsmGetFi(fsm);
01402                 *te = '\0';
01403                 st->st_mode = S_IFDIR | (fi->dperms & 07777);
01404                 rc = fsmNext(fsm, FSM_MKDIR);
01405                 if (!rc) {
01406                     /* XXX FIXME? only new dir will have context set. */
01407                     /* Get file security context from patterns. */
01408                     if (sx != NULL) {
01409                         fsm->fcontext = rpmsxFContext(sx, fsm->path, st->st_mode);
01410                         rc = fsmNext(fsm, FSM_LSETFCON);
01411                     }
01412                     if (fsm->fcontext == NULL)
01413                         rpmMessage(RPMMESS_DEBUG,
01414                             D_("%s directory created with perms %04o, no context.\n"),
01415                             fsm->path, (unsigned)(st->st_mode & 07777));
01416                     else
01417                         rpmMessage(RPMMESS_DEBUG,
01418                             D_("%s directory created with perms %04o, context %s.\n"),
01419                             fsm->path, (unsigned)(st->st_mode & 07777),
01420                             fsm->fcontext);
01421                     fsm->fcontext = NULL;
01422                 }
01423                 *te = '/';
01424             }
01425             if (rc)
01426                 /*@innerbreak@*/ break;
01427         }
01428         if (rc) break;
01429 
01430         /* Save last validated path. */
01431 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01432         if (fsm->ldnalloc < (dnlen + 1)) {
01433             fsm->ldnalloc = dnlen + 100;
01434             fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
01435         }
01436         if (fsm->ldn != NULL) { /* XXX can't happen */
01437             strcpy(fsm->ldn, fsm->path);
01438             fsm->ldnlen = dnlen;
01439         }
01440 /*@=compdef@*/
01441     }
01442 /*@=boundswrite@*/
01443     dnli = dnlFreeIterator(dnli);
01444     sx = rpmsxFree(sx);
01445     /*@=observertrans =dependenttrans@*/
01446 
01447     fsm->path = path;
01448     st->st_mode = st_mode;              /* XXX restore st->st_mode */
01449 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01450     return rc;
01451 /*@=compdef@*/
01452 }
01453 
01454 #ifdef  NOTYET
01455 
01460 static int fsmStat(/*@special@*/ /*@partial@*/ FSM_t fsm)
01461         /*@globals fileSystem, internalState @*/
01462         /*@modifies fsm, fileSystem, internalState @*/
01463 {
01464     int rc = 0;
01465 
01466     if (fsm->path != NULL) {
01467         int saveernno = errno;
01468         rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
01469                         ? FSM_LSTAT : FSM_STAT));
01470         if (rc == CPIOERR_ENOENT) {
01471             errno = saveerrno;
01472             rc = 0;
01473             fsm->exists = 0;
01474         } else if (rc == 0) {
01475             fsm->exists = 1;
01476         }
01477     } else {
01478         /* Skip %ghost files on build. */
01479         fsm->exists = 0;
01480     }
01481     return rc;
01482 }
01483 #endif
01484 
01485 #define IS_DEV_LOG(_x)  \
01486         ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
01487         !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \
01488         ((_x)[sizeof("/dev/log")-1] == '\0' || \
01489          (_x)[sizeof("/dev/log")-1] == ';'))
01490 
01491 /*@-boundsread@*/
01492 /*@-compmempass@*/
01493 int fsmStage(FSM_t fsm, fileStage stage)
01494 {
01495 #ifdef  UNUSED
01496     fileStage prevStage = fsm->stage;
01497     const char * const prev = fileStageString(prevStage);
01498 #endif
01499     const char * const cur = fileStageString(stage);
01500     struct stat * st = &fsm->sb;
01501     struct stat * ost = &fsm->osb;
01502     int saveerrno = errno;
01503     int rc = fsm->rc;
01504     size_t left;
01505     int i;
01506 
01507 #define _fafilter(_a)   \
01508     (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
01509         ? fileActionString(_a) : "")
01510 
01511     if (stage & FSM_DEAD) {
01512         /* do nothing */
01513     } else if (stage & FSM_INTERNAL) {
01514         if (_fsm_debug && !(stage & FSM_SYSCALL))
01515             rpmMessage(RPMMESS_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n",
01516                 cur,
01517                 (unsigned)st->st_mode, (int)st->st_nlink,
01518                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01519                 (fsm->path ? fsm->path : ""),
01520                 _fafilter(fsm->action));
01521     } else {
01522         const char * apath = NULL;
01523         if (fsm->path)
01524             (void) urlPath(fsm->path, &apath);
01525         fsm->stage = stage;
01526         if (_fsm_debug || !(stage & FSM_VERBOSE))
01527             rpmMessage(RPMMESS_DEBUG, "%-8s  %06o%3d (%4d,%4d)%12lu %s %s\n",
01528                 cur,
01529                 (unsigned)st->st_mode, (int)st->st_nlink,
01530                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01531                 (fsm->path ? apath + fsm->astriplen : ""),
01532                 _fafilter(fsm->action));
01533     }
01534 #undef  _fafilter
01535 
01536     /*@-branchstate@*/
01537     switch (stage) {
01538     case FSM_UNKNOWN:
01539         break;
01540     case FSM_PKGINSTALL:
01541         while (1) {
01542             /* Clean fsm, free'ing memory. Read next archive header. */
01543             rc = fsmUNSAFE(fsm, FSM_INIT);
01544 
01545             /* Exit on end-of-payload. */
01546             if (rc == CPIOERR_HDR_TRAILER) {
01547                 rc = 0;
01548                 /*@loopbreak@*/ break;
01549             }
01550 
01551             /* Exit on error. */
01552             if (rc) {
01553                 fsm->postpone = 1;
01554                 (void) fsmNext(fsm, FSM_UNDO);
01555                 /*@loopbreak@*/ break;
01556             }
01557 
01558             /* Extract file from archive. */
01559             rc = fsmNext(fsm, FSM_PROCESS);
01560             if (rc) {
01561                 (void) fsmNext(fsm, FSM_UNDO);
01562                 /*@loopbreak@*/ break;
01563             }
01564 
01565             /* Notify on success. */
01566             (void) fsmNext(fsm, FSM_NOTIFY);
01567 
01568             rc = fsmNext(fsm, FSM_FINI);
01569             if (rc) {
01570                 /*@loopbreak@*/ break;
01571             }
01572         }
01573         break;
01574     case FSM_PKGERASE:
01575     case FSM_PKGCOMMIT:
01576         while (1) {
01577             /* Clean fsm, free'ing memory. */
01578             rc = fsmUNSAFE(fsm, FSM_INIT);
01579 
01580             /* Exit on end-of-payload. */
01581             if (rc == CPIOERR_HDR_TRAILER) {
01582                 rc = 0;
01583                 /*@loopbreak@*/ break;
01584             }
01585 
01586             /* Rename/erase next item. */
01587             if (fsmNext(fsm, FSM_FINI))
01588                 /*@loopbreak@*/ break;
01589         }
01590         break;
01591     case FSM_PKGBUILD:
01592         while (1) {
01593 
01594             rc = fsmUNSAFE(fsm, FSM_INIT);
01595 
01596             /* Exit on end-of-payload. */
01597             if (rc == CPIOERR_HDR_TRAILER) {
01598                 rc = 0;
01599                 /*@loopbreak@*/ break;
01600             }
01601 
01602             /* Exit on error. */
01603             if (rc) {
01604                 fsm->postpone = 1;
01605                 (void) fsmNext(fsm, FSM_UNDO);
01606                 /*@loopbreak@*/ break;
01607             }
01608 
01609             /* Copy file into archive. */
01610             rc = fsmNext(fsm, FSM_PROCESS);
01611             if (rc) {
01612                 (void) fsmNext(fsm, FSM_UNDO);
01613                 /*@loopbreak@*/ break;
01614             }
01615 
01616             /* Notify on success. */
01617             (void) fsmNext(fsm, FSM_NOTIFY);
01618 
01619             if (fsmNext(fsm, FSM_FINI))
01620                 /*@loopbreak@*/ break;
01621         }
01622 
01623         /* Flush partial sets of hard linked files. */
01624         if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) {
01625             int nlink, j;
01626             while ((fsm->li = fsm->links) != NULL) {
01627                 fsm->links = fsm->li->next;
01628                 fsm->li->next = NULL;
01629 
01630                 /* Re-calculate link count for archive header. */
01631                 for (j = -1, nlink = 0, i = 0; i < fsm->li->nlink; i++) {
01632                     if (fsm->li->filex[i] < 0)
01633                         /*@innercontinue@*/ continue;
01634                     nlink++;
01635                     if (j == -1) j = i;
01636                 }
01637                 /* XXX force the contents out as well. */
01638 /*@-boundswrite@*/
01639                 if (j != 0) {
01640                     fsm->li->filex[0] = fsm->li->filex[j];
01641                     fsm->li->filex[j] = -1;
01642                 }
01643 /*@=boundswrite@*/
01644                 fsm->li->sb.st_nlink = nlink;
01645 
01646                 fsm->sb = fsm->li->sb;  /* structure assignment */
01647                 fsm->osb = fsm->sb;     /* structure assignment */
01648 
01649                 if (!rc) rc = writeLinkedFile(fsm);
01650 
01651                 fsm->li = freeHardLink(fsm->li);
01652             }
01653         }
01654 
01655         if (!rc)
01656             rc = fsmNext(fsm, FSM_TRAILER);
01657 
01658         break;
01659     case FSM_CREATE:
01660         {   rpmts ts = fsmGetTs(fsm);
01661 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
01662             fsm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) &&
01663                         fsm->goal != FSM_PKGCOMMIT) ? 0 : 1);
01664 #undef _tsmask
01665         }
01666         fsm->path = _free(fsm->path);
01667         fsm->lpath = _free(fsm->lpath);
01668         fsm->opath = _free(fsm->opath);
01669         fsm->dnlx = _free(fsm->dnlx);
01670 
01671         fsm->ldn = _free(fsm->ldn);
01672         fsm->ldnalloc = fsm->ldnlen = 0;
01673 
01674         fsm->rdsize = fsm->wrsize = 0;
01675         fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
01676         fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
01677         if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
01678             fsm->rdsize = 8 * BUFSIZ;
01679             fsm->rdbuf = fsm->rdb = xmalloc(fsm->rdsize);
01680             fsm->wrsize = 8 * BUFSIZ;
01681             fsm->wrbuf = fsm->wrb = xmalloc(fsm->wrsize);
01682         }
01683 
01684         fsm->mkdirsdone = 0;
01685         fsm->ix = -1;
01686         fsm->links = NULL;
01687         fsm->li = NULL;
01688         errno = 0;      /* XXX get rid of EBADF */
01689 
01690         /* Detect and create directories not explicitly in package. */
01691         if (fsm->goal == FSM_PKGINSTALL) {
01692 /*@-compdef@*/
01693             rc = fsmNext(fsm, FSM_MKDIRS);
01694 /*@=compdef@*/
01695             if (!rc) fsm->mkdirsdone = 1;
01696         }
01697 
01698         break;
01699     case FSM_INIT:
01700         fsm->path = _free(fsm->path);
01701         fsm->lpath = _free(fsm->lpath);
01702         fsm->postpone = 0;
01703         fsm->diskchecked = fsm->exists = 0;
01704         fsm->subdir = NULL;
01705         fsm->suffix = (fsm->sufbuf[0] != '\0' ? fsm->sufbuf : NULL);
01706         fsm->action = FA_UNKNOWN;
01707         fsm->osuffix = NULL;
01708         fsm->nsuffix = NULL;
01709 
01710         if (fsm->goal == FSM_PKGINSTALL) {
01711             /* Read next header from payload, checking for end-of-payload. */
01712             rc = fsmUNSAFE(fsm, FSM_NEXT);
01713         }
01714         if (rc) break;
01715 
01716         /* Identify mapping index. */
01717         fsm->ix = ((fsm->goal == FSM_PKGINSTALL)
01718                 ? mapFind(fsm->iter, fsm->path) : mapNextIterator(fsm->iter));
01719 
01720 if (!(fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_LIST)) {
01721         /* Detect end-of-loop and/or mapping error. */
01722 if (!(fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_EXTRACT)) {
01723         if (fsm->ix < 0) {
01724             if (fsm->goal == FSM_PKGINSTALL) {
01725 #if 0
01726                 rpmMessage(RPMMESS_WARNING,
01727                     _("archive file %s was not found in header file list\n"),
01728                         fsm->path);
01729 #endif
01730 /*@-boundswrite@*/
01731                 if (fsm->failedFile && *fsm->failedFile == NULL)
01732                     *fsm->failedFile = xstrdup(fsm->path);
01733 /*@=boundswrite@*/
01734                 rc = CPIOERR_UNMAPPED_FILE;
01735             } else {
01736                 rc = CPIOERR_HDR_TRAILER;
01737             }
01738             break;
01739         }
01740 }
01741 
01742         /* On non-install, mode must be known so that dirs don't get suffix. */
01743         if (fsm->goal != FSM_PKGINSTALL) {
01744             rpmfi fi = fsmGetFi(fsm);
01745             st->st_mode = fi->fmodes[fsm->ix];
01746         }
01747 }
01748 
01749         /* Generate file path. */
01750         rc = fsmNext(fsm, FSM_MAP);
01751         if (rc) break;
01752 
01753         /* Perform lstat/stat for disk file. */
01754 #ifdef  NOTYET
01755         rc = fsmStat(fsm);
01756 #else
01757         if (fsm->path != NULL &&
01758             !(fsm->goal == FSM_PKGINSTALL && S_ISREG(st->st_mode)))
01759         {
01760             rc = fsmUNSAFE(fsm, (!(fsm->mapFlags & CPIO_FOLLOW_SYMLINKS)
01761                         ? FSM_LSTAT : FSM_STAT));
01762             if (rc == CPIOERR_ENOENT) {
01763                 errno = saveerrno;
01764                 rc = 0;
01765                 fsm->exists = 0;
01766             } else if (rc == 0) {
01767                 fsm->exists = 1;
01768             }
01769         } else {
01770             /* Skip %ghost files on build. */
01771             fsm->exists = 0;
01772         }
01773 #endif
01774         fsm->diskchecked = 1;
01775         if (rc) break;
01776 
01777         /* On non-install, the disk file stat is what's remapped. */
01778 /*@-boundswrite@*/
01779         if (fsm->goal != FSM_PKGINSTALL)
01780             *st = *ost;                 /* structure assignment */
01781 /*@=boundswrite@*/
01782 
01783         /* Remap file perms, owner, and group. */
01784         rc = fsmMapAttrs(fsm);
01785         if (rc) break;
01786 
01787         fsm->postpone = XFA_SKIPPING(fsm->action);
01788         if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
01789             /*@-evalorder@*/ /* FIX: saveHardLink can modify fsm */
01790             if (!(S_ISDIR(st->st_mode) || S_ISLNK(st->st_mode))
01791              && (st->st_nlink > 1 || fsm->lpath != NULL))
01792                 fsm->postpone = saveHardLink(fsm);
01793             /*@=evalorder@*/
01794         }
01795 if (fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_LIST) fsm->postpone = 1;
01796         break;
01797     case FSM_PRE:
01798         break;
01799     case FSM_MAP:
01800         rc = fsmMapPath(fsm);
01801         break;
01802     case FSM_MKDIRS:
01803         rc = fsmMkdirs(fsm);
01804         break;
01805     case FSM_RMDIRS:
01806         if (fsm->dnlx)
01807             rc = fsmRmdirs(fsm);
01808         break;
01809     case FSM_PROCESS:
01810         if (fsm->postpone) {
01811             if (fsm->goal == FSM_PKGINSTALL) {
01812                 /* XXX Skip over file body, archive headers already done. */
01813                 if (S_ISREG(st->st_mode))
01814                     rc = fsmNext(fsm, FSM_EAT);
01815             }
01816             break;
01817         }
01818 
01819         if (fsm->goal == FSM_PKGBUILD) {
01820             if (fsm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
01821                 break;
01822             if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
01823                 struct hardLink_s * li, * prev;
01824 
01825 if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) break;
01826                 rc = writeLinkedFile(fsm);
01827                 if (rc) break;  /* W2DO? */
01828 
01829                 for (li = fsm->links, prev = NULL; li; prev = li, li = li->next)
01830                      if (li == fsm->li)
01831                         /*@loopbreak@*/ break;
01832 
01833                 if (prev == NULL)
01834                     fsm->links = fsm->li->next;
01835                 else
01836                     prev->next = fsm->li->next;
01837                 fsm->li->next = NULL;
01838                 fsm->li = freeHardLink(fsm->li);
01839             } else {
01840                 rc = writeFile(fsm, 1);
01841             }
01842             break;
01843         }
01844 
01845         if (fsm->goal != FSM_PKGINSTALL)
01846             break;
01847 
01848         if (S_ISREG(st->st_mode) && fsm->lpath != NULL) {
01849             const char * opath = fsm->opath;
01850             char * t = xmalloc(strlen(fsm->lpath+1) + strlen(fsm->suffix) + 1);
01851             (void) stpcpy(t, fsm->lpath+1);
01852              fsm->opath = t;
01853             /* XXX link(fsm->opath, fsm->path) */
01854             rc = fsmNext(fsm, FSM_LINK);
01855             if (fsm->failedFile && rc != 0 && *fsm->failedFile == NULL) {
01856 /*@-boundswrite@*/
01857                 *fsm->failedFile = xstrdup(fsm->path);
01858 /*@=boundswrite@*/
01859             }
01860             fsm->opath = _free(fsm->opath);
01861             fsm->opath = opath;
01862             break;      /* XXX so that delayed hard links get skipped. */
01863         }
01864         if (S_ISREG(st->st_mode)) {
01865             const char * path = fsm->path;
01866             if (fsm->osuffix)
01867                 fsm->path = fsmFsPath(fsm, st, NULL, NULL);
01868             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01869 
01870             if (rc == 0 && fsm->osuffix) {
01871                 const char * opath = fsm->opath;
01872                 fsm->opath = fsm->path;
01873                 fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
01874                 rc = fsmNext(fsm, FSM_RENAME);
01875                 if (!rc)
01876                     rpmMessage(RPMMESS_WARNING,
01877                         _("%s saved as %s\n"),
01878                                 (fsm->opath ? fsm->opath : ""),
01879                                 (fsm->path ? fsm->path : ""));
01880                 fsm->path = _free(fsm->path);
01881                 fsm->opath = opath;
01882             }
01883 
01884             /*@-dependenttrans@*/
01885             fsm->path = path;
01886             /*@=dependenttrans@*/
01887             if (!(rc == CPIOERR_ENOENT)) return rc;
01888             rc = extractRegular(fsm);
01889         } else if (S_ISDIR(st->st_mode)) {
01890             mode_t st_mode = st->st_mode;
01891             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01892             if (rc == CPIOERR_ENOENT) {
01893                 st->st_mode &= ~07777;          /* XXX abuse st->st_mode */
01894                 st->st_mode |=  00700;
01895                 rc = fsmNext(fsm, FSM_MKDIR);
01896                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
01897             }
01898         } else if (S_ISLNK(st->st_mode)) {
01899 assert(fsm->lpath != NULL);
01900             /*@=dependenttrans@*/
01901             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01902             if (rc == CPIOERR_ENOENT)
01903                 rc = fsmNext(fsm, FSM_SYMLINK);
01904         } else if (S_ISFIFO(st->st_mode)) {
01905             mode_t st_mode = st->st_mode;
01906             /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
01907             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01908             if (rc == CPIOERR_ENOENT) {
01909                 st->st_mode = 0000;             /* XXX abuse st->st_mode */
01910                 rc = fsmNext(fsm, FSM_MKFIFO);
01911                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
01912             }
01913         } else if (S_ISCHR(st->st_mode) ||
01914                    S_ISBLK(st->st_mode) ||
01915     /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
01916         {
01917             rc = fsmUNSAFE(fsm, FSM_VERIFY);
01918             if (rc == CPIOERR_ENOENT)
01919                 rc = fsmNext(fsm, FSM_MKNOD);
01920         } else {
01921             /* XXX Repackaged payloads may be missing files. */
01922             if (fsm->repackaged)
01923                 break;
01924 
01925             /* XXX Special case /dev/log, which shouldn't be packaged anyways */
01926             if (!IS_DEV_LOG(fsm->path))
01927                 rc = CPIOERR_UNKNOWN_FILETYPE;
01928         }
01929         if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
01930             fsm->li->createdPath = fsm->li->linkIndex;
01931             rc = fsmMakeLinks(fsm);
01932         }
01933         break;
01934     case FSM_POST:
01935         break;
01936     case FSM_MKLINKS:
01937         rc = fsmMakeLinks(fsm);
01938         break;
01939     case FSM_NOTIFY:            /* XXX move from fsm to psm -> tsm */
01940         if (fsm->goal == FSM_PKGINSTALL || fsm->goal == FSM_PKGBUILD) {
01941             rpmts ts = fsmGetTs(fsm);
01942             rpmfi fi = fsmGetFi(fsm);
01943             void * ptr;
01944             unsigned long long archivePos = fdGetCpioPos(fsm->cfd);
01945             if (archivePos > fi->archivePos) {
01946                 fi->archivePos = archivePos;
01947                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS,
01948                         fi->archivePos, fi->archiveSize);
01949             }
01950         }
01951         break;
01952     case FSM_UNDO:
01953         if (fsm->postpone)
01954             break;
01955         if (fsm->goal == FSM_PKGINSTALL) {
01956             /* XXX only erase if temp fn w suffix is in use */
01957             if (fsm->sufbuf[0] != '\0')
01958                 (void) fsmNext(fsm,
01959                     (S_ISDIR(st->st_mode) ? FSM_RMDIR : FSM_UNLINK));
01960 
01961 #ifdef  NOTYET  /* XXX remove only dirs just created, not all. */
01962             if (fsm->dnlx)
01963                 (void) fsmNext(fsm, FSM_RMDIRS);
01964 #endif
01965             errno = saveerrno;
01966         }
01967 /*@-boundswrite@*/
01968         if (fsm->failedFile && *fsm->failedFile == NULL)
01969             *fsm->failedFile = xstrdup(fsm->path);
01970 /*@=boundswrite@*/
01971         break;
01972     case FSM_FINI:
01973         if (!fsm->postpone && fsm->commit) {
01974             if (fsm->goal == FSM_PKGINSTALL)
01975                 rc = ((!S_ISDIR(st->st_mode) && st->st_nlink > 1)
01976                         ? fsmCommitLinks(fsm) : fsmNext(fsm, FSM_COMMIT));
01977             if (fsm->goal == FSM_PKGCOMMIT)
01978                 rc = fsmNext(fsm, FSM_COMMIT);
01979             if (fsm->goal == FSM_PKGERASE)
01980                 rc = fsmNext(fsm, FSM_COMMIT);
01981         }
01982         fsm->path = _free(fsm->path);
01983         fsm->lpath = _free(fsm->lpath);
01984         fsm->opath = _free(fsm->opath);
01985 /*@-boundswrite@*/
01986         memset(st, 0, sizeof(*st));
01987         memset(ost, 0, sizeof(*ost));
01988 /*@=boundswrite@*/
01989         break;
01990     case FSM_COMMIT:
01991         /* Rename pre-existing modified or unmanaged file. */
01992         if (fsm->osuffix && fsm->diskchecked &&
01993           (fsm->exists || (fsm->goal == FSM_PKGINSTALL && S_ISREG(st->st_mode))))
01994         {
01995             const char * opath = fsm->opath;
01996             const char * path = fsm->path;
01997             fsm->opath = fsmFsPath(fsm, st, NULL, NULL);
01998             fsm->path = fsmFsPath(fsm, st, NULL, fsm->osuffix);
01999             rc = fsmNext(fsm, FSM_RENAME);
02000             if (!rc) {
02001                 rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"),
02002                                 (fsm->opath ? fsm->opath : ""),
02003                                 (fsm->path ? fsm->path : ""));
02004             }
02005             fsm->path = _free(fsm->path);
02006             fsm->path = path;
02007             fsm->opath = _free(fsm->opath);
02008             fsm->opath = opath;
02009         }
02010 
02011         /* Remove erased files. */
02012         if (fsm->goal == FSM_PKGERASE) {
02013             if (fsm->action == FA_ERASE) {
02014                 rpmfi fi = fsmGetFi(fsm);
02015                 if (S_ISDIR(st->st_mode)) {
02016                     rc = fsmNext(fsm, FSM_RMDIR);
02017                     if (!rc) break;
02018                     switch (rc) {
02019                     case CPIOERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
02020                     case CPIOERR_ENOTEMPTY:
02021         /* XXX make sure that build side permits %missingok on directories. */
02022                         if (fsm->fflags & RPMFILE_MISSINGOK)
02023                             /*@innerbreak@*/ break;
02024 
02025                         /* XXX common error message. */
02026                         rpmError(
02027                             (strict_erasures ? RPMERR_RMDIR : RPMDEBUG_RMDIR),
02028                             _("%s rmdir of %s failed: Directory not empty\n"), 
02029                                 rpmfiTypeString(fi), fsm->path);
02030                         /*@innerbreak@*/ break;
02031                     default:
02032                         rpmError(
02033                             (strict_erasures ? RPMERR_RMDIR : RPMDEBUG_RMDIR),
02034                                 _("%s rmdir of %s failed: %s\n"),
02035                                 rpmfiTypeString(fi), fsm->path, strerror(errno));
02036                         /*@innerbreak@*/ break;
02037                     }
02038                 } else {
02039                     rc = fsmNext(fsm, FSM_UNLINK);
02040                     if (!rc) break;
02041                     switch (rc) {
02042                     case CPIOERR_ENOENT:
02043                         if (fsm->fflags & RPMFILE_MISSINGOK)
02044                             /*@innerbreak@*/ break;
02045                         /*@fallthrough@*/
02046                     default:
02047                         rpmError(
02048                             (strict_erasures ? RPMERR_UNLINK : RPMDEBUG_UNLINK),
02049                                 _(" %s: unlink of %s failed: %s\n"),
02050                                 rpmfiTypeString(fi), fsm->path, strerror(errno));
02051                         /*@innerbreak@*/ break;
02052                     }
02053                 }
02054             }
02055             /* XXX Failure to remove is not (yet) cause for failure. */
02056             if (!strict_erasures) rc = 0;
02057             break;
02058         }
02059 
02060         /* XXX Special case /dev/log, which shouldn't be packaged anyways */
02061 if (!(fsmGetFi(fsm)->mapflags & CPIO_PAYLOAD_EXTRACT)) {
02062         if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(fsm->path)) {
02063             /* Rename temporary to final file name. */
02064             if (!S_ISDIR(st->st_mode) &&
02065                 (fsm->subdir || fsm->suffix || fsm->nsuffix))
02066             {
02067                 fsm->opath = fsm->path;
02068                 fsm->path = fsmFsPath(fsm, st, NULL, fsm->nsuffix);
02069                 rc = fsmNext(fsm, FSM_RENAME);
02070                 if (rc)
02071                         (void) Unlink(fsm->opath);
02072                 else if (fsm->nsuffix) {
02073                     const char * opath = fsmFsPath(fsm, st, NULL, NULL);
02074                     rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"),
02075                                 (opath ? opath : ""),
02076                                 (fsm->path ? fsm->path : ""));
02077                     opath = _free(opath);
02078                 }
02079                 fsm->opath = _free(fsm->opath);
02080             }
02081             /*
02082              * Set file security context (if not disabled).
02083              */
02084             if (!rc && !getuid()) {
02085                 rc = fsmMapFContext(fsm);
02086                 if (!rc)
02087                     rc = fsmNext(fsm, FSM_LSETFCON);
02088                 fsm->fcontext = NULL;
02089             }
02090             if (S_ISLNK(st->st_mode)) {
02091                 if (!rc && !getuid())
02092                     rc = fsmNext(fsm, FSM_LCHOWN);
02093             } else {
02094                 if (!rc && !getuid())
02095                     rc = fsmNext(fsm, FSM_CHOWN);
02096                 if (!rc)
02097                     rc = fsmNext(fsm, FSM_CHMOD);
02098                 if (!rc) {
02099                     time_t mtime = st->st_mtime;
02100                     rpmfi fi = fsmGetFi(fsm);
02101                     if (fi->fmtimes)
02102                         st->st_mtime = fi->fmtimes[fsm->ix];
02103                     rc = fsmNext(fsm, FSM_UTIME);
02104                     st->st_mtime = mtime;
02105                 }
02106             }
02107         }
02108 }
02109 
02110         /* Notify on success. */
02111         if (!rc)                rc = fsmNext(fsm, FSM_NOTIFY);
02112         else if (fsm->failedFile && *fsm->failedFile == NULL) {
02113 /*@-boundswrite@*/
02114             *fsm->failedFile = fsm->path;
02115 /*@=boundswrite@*/
02116             fsm->path = NULL;
02117         }
02118         break;
02119     case FSM_DESTROY:
02120         fsm->path = _free(fsm->path);
02121 
02122         /* Check for hard links missing from payload. */
02123         while ((fsm->li = fsm->links) != NULL) {
02124             fsm->links = fsm->li->next;
02125             fsm->li->next = NULL;
02126             if (fsm->goal == FSM_PKGINSTALL &&
02127                         fsm->commit && fsm->li->linksLeft)
02128             {
02129                 for (i = 0 ; i < fsm->li->linksLeft; i++) {
02130                     if (fsm->li->filex[i] < 0)
02131                         /*@innercontinue@*/ continue;
02132                     rc = CPIOERR_MISSING_HARDLINK;
02133                     if (fsm->failedFile && *fsm->failedFile == NULL) {
02134                         fsm->ix = fsm->li->filex[i];
02135                         if (!fsmNext(fsm, FSM_MAP)) {
02136 /*@-boundswrite@*/
02137                             *fsm->failedFile = fsm->path;
02138 /*@=boundswrite@*/
02139                             fsm->path = NULL;
02140                         }
02141                     }
02142                     /*@loopbreak@*/ break;
02143                 }
02144             }
02145             if (fsm->goal == FSM_PKGBUILD &&
02146                 (fsm->mapFlags & CPIO_ALL_HARDLINKS))
02147             {
02148                 rc = CPIOERR_MISSING_HARDLINK;
02149             }
02150             fsm->li = freeHardLink(fsm->li);
02151         }
02152         fsm->ldn = _free(fsm->ldn);
02153         fsm->ldnalloc = fsm->ldnlen = 0;
02154         fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
02155         fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
02156         break;
02157     case FSM_VERIFY:
02158         if (fsm->diskchecked && !fsm->exists) {
02159             rc = CPIOERR_ENOENT;
02160             break;
02161         }
02162         if (S_ISREG(st->st_mode)) {
02163             char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
02164 /*@-boundswrite@*/
02165             (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
02166 /*@=boundswrite@*/
02167             /*
02168              * XXX HP-UX (and other os'es) don't permit unlink on busy
02169              * XXX files.
02170              */
02171             fsm->opath = fsm->path;
02172             fsm->path = path;
02173             rc = fsmNext(fsm, FSM_RENAME);
02174             if (!rc)
02175                     (void) fsmNext(fsm, FSM_UNLINK);
02176             else
02177                     rc = CPIOERR_UNLINK_FAILED;
02178             fsm->path = fsm->opath;
02179             fsm->opath = NULL;
02180             return (rc ? rc : CPIOERR_ENOENT);  /* XXX HACK */
02181             /*@notreached@*/ break;
02182         } else if (S_ISDIR(st->st_mode)) {
02183             if (S_ISDIR(ost->st_mode))          return 0;
02184             if (S_ISLNK(ost->st_mode)) {
02185                 rc = fsmUNSAFE(fsm, FSM_STAT);
02186                 if (rc == CPIOERR_ENOENT) rc = 0;
02187                 if (rc) break;
02188                 errno = saveerrno;
02189                 if (S_ISDIR(ost->st_mode))      return 0;
02190             }
02191         } else if (S_ISLNK(st->st_mode)) {
02192             if (S_ISLNK(ost->st_mode)) {
02193         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
02194                 rc = fsmUNSAFE(fsm, FSM_READLINK);
02195                 errno = saveerrno;
02196                 if (rc) break;
02197                 if (!strcmp(fsm->lpath, fsm->rdbuf))    return 0;
02198             }
02199         } else if (S_ISFIFO(st->st_mode)) {
02200             if (S_ISFIFO(ost->st_mode))         return 0;
02201         } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
02202             if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
02203                 (ost->st_rdev == st->st_rdev))  return 0;
02204         } else if (S_ISSOCK(st->st_mode)) {
02205             if (S_ISSOCK(ost->st_mode))         return 0;
02206         }
02207             /* XXX shouldn't do this with commit/undo. */
02208         rc = 0;
02209         if (fsm->stage == FSM_PROCESS) rc = fsmNext(fsm, FSM_UNLINK);
02210         if (rc == 0)    rc = CPIOERR_ENOENT;
02211         return (rc ? rc : CPIOERR_ENOENT);      /* XXX HACK */
02212         /*@notreached@*/ break;
02213 
02214     case FSM_UNLINK:
02215         /* XXX Remove setuid/setgid bits on possibly hard linked files. */
02216         if (fsm->mapFlags & CPIO_SBIT_CHECK) {
02217             struct stat stb;
02218             if (Lstat(fsm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
02219                 /* XXX rc = fsmNext(fsm, FSM_CHMOD); instead */
02220                 int xx = chmod(fsm->path, stb.st_mode & 0777);
02221             }
02222         }
02223         rc = Unlink(fsm->path);
02224         if (_fsm_debug && (stage & FSM_SYSCALL))
02225             rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
02226                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02227         if (rc < 0)
02228             rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_UNLINK_FAILED);
02229         break;
02230     case FSM_RENAME:
02231         /* XXX Remove setuid/setgid bits on possibly hard linked files. */
02232         if (fsm->mapFlags & CPIO_SBIT_CHECK) {
02233             struct stat stb;
02234             if (Lstat(fsm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
02235                 /* XXX rc = fsmNext(fsm, FSM_CHMOD); instead */
02236                 int xx = chmod(fsm->path, stb.st_mode & 0777);
02237             }
02238         }
02239         rc = Rename(fsm->opath, fsm->path);
02240         /* XXX Repackaged payloads may be missing files. */
02241         if (fsm->repackaged)
02242             rc = 0;
02243 #if defined(ETXTBSY)
02244         if (rc && errno == ETXTBSY) {
02245             char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
02246             (void) stpcpy( stpcpy(path, fsm->path), "-RPMDELETE");
02247             /*
02248              * XXX HP-UX (and other os'es) don't permit rename to busy
02249              * XXX files.
02250              */
02251             rc = Rename(fsm->path, path);
02252             if (!rc) rc = Rename(fsm->opath, fsm->path);
02253         }
02254 #endif
02255         if (_fsm_debug && (stage & FSM_SYSCALL))
02256             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02257                 fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
02258         if (rc < 0)     rc = CPIOERR_RENAME_FAILED;
02259         break;
02260     case FSM_MKDIR:
02261         rc = Mkdir(fsm->path, (st->st_mode & 07777));
02262         if (_fsm_debug && (stage & FSM_SYSCALL))
02263             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02264                 fsm->path, (unsigned)(st->st_mode & 07777),
02265                 (rc < 0 ? strerror(errno) : ""));
02266         if (rc < 0)     rc = CPIOERR_MKDIR_FAILED;
02267         break;
02268     case FSM_RMDIR:
02269         rc = Rmdir(fsm->path);
02270         if (_fsm_debug && (stage & FSM_SYSCALL))
02271             rpmMessage(RPMMESS_DEBUG, " %8s (%s) %s\n", cur,
02272                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02273         if (rc < 0)
02274             switch (errno) {
02275             case ENOENT:        rc = CPIOERR_ENOENT;    /*@switchbreak@*/ break;
02276             case ENOTEMPTY:     rc = CPIOERR_ENOTEMPTY; /*@switchbreak@*/ break;
02277             default:            rc = CPIOERR_RMDIR_FAILED; /*@switchbreak@*/ break;
02278             }
02279         break;
02280     case FSM_LSETFCON:
02281       { const char * fsmpath = NULL;
02282         if (fsm->fcontext == NULL || *fsm->fcontext == '\0'
02283          || !strcmp(fsm->fcontext, "<<none>>"))
02284             break;
02285         (void) urlPath(fsm->path, &fsmpath);    /* XXX fsm->path */
02286         rc = lsetfilecon(fsmpath, (security_context_t)fsm->fcontext);
02287         if (_fsm_debug && (stage & FSM_SYSCALL))
02288             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02289                 fsm->path, fsm->fcontext,
02290                 (rc < 0 ? strerror(errno) : ""));
02291         if (rc < 0) rc = (errno == EOPNOTSUPP ? 0 : CPIOERR_LSETFCON_FAILED);
02292       } break;
02293     case FSM_CHOWN:
02294         rc = Chown(fsm->path, st->st_uid, st->st_gid);
02295         if (_fsm_debug && (stage & FSM_SYSCALL))
02296             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
02297                 fsm->path, (int)st->st_uid, (int)st->st_gid,
02298                 (rc < 0 ? strerror(errno) : ""));
02299         if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
02300         break;
02301     case FSM_LCHOWN:
02302 #if ! CHOWN_FOLLOWS_SYMLINK
02303         rc = Lchown(fsm->path, st->st_uid, st->st_gid);
02304         if (_fsm_debug && (stage & FSM_SYSCALL))
02305             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
02306                 fsm->path, (int)st->st_uid, (int)st->st_gid,
02307                 (rc < 0 ? strerror(errno) : ""));
02308         if (rc < 0)     rc = CPIOERR_CHOWN_FAILED;
02309 #endif
02310         break;
02311     case FSM_CHMOD:
02312         rc = Chmod(fsm->path, (st->st_mode & 07777));
02313         if (_fsm_debug && (stage & FSM_SYSCALL))
02314             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02315                 fsm->path, (unsigned)(st->st_mode & 07777),
02316                 (rc < 0 ? strerror(errno) : ""));
02317         if (rc < 0)     rc = CPIOERR_CHMOD_FAILED;
02318         break;
02319     case FSM_UTIME:
02320         {   struct utimbuf stamp;
02321             stamp.actime = st->st_mtime;
02322             stamp.modtime = st->st_mtime;
02323             rc = Utime(fsm->path, &stamp);
02324             if (_fsm_debug && (stage & FSM_SYSCALL))
02325                 rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
02326                         fsm->path, (unsigned)st->st_mtime,
02327                         (rc < 0 ? strerror(errno) : ""));
02328             if (rc < 0) rc = CPIOERR_UTIME_FAILED;
02329         }
02330         break;
02331     case FSM_SYMLINK:
02332         rc = Symlink(fsm->lpath, fsm->path);
02333         if (_fsm_debug && (stage & FSM_SYSCALL))
02334             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02335                 fsm->lpath, fsm->path, (rc < 0 ? strerror(errno) : ""));
02336         if (rc < 0)     rc = CPIOERR_SYMLINK_FAILED;
02337         break;
02338     case FSM_LINK:
02339         rc = Link(fsm->opath, fsm->path);
02340         if (_fsm_debug && (stage & FSM_SYSCALL))
02341             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
02342                 fsm->opath, fsm->path, (rc < 0 ? strerror(errno) : ""));
02343         if (rc < 0)     rc = CPIOERR_LINK_FAILED;
02344         break;
02345     case FSM_MKFIFO:
02346         rc = Mkfifo(fsm->path, (st->st_mode & 07777));
02347         if (_fsm_debug && (stage & FSM_SYSCALL))
02348             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02349                 fsm->path, (unsigned)(st->st_mode & 07777),
02350                 (rc < 0 ? strerror(errno) : ""));
02351         if (rc < 0)     rc = CPIOERR_MKFIFO_FAILED;
02352         break;
02353     case FSM_MKNOD:
02354         /*@-unrecog -portability @*/ /* FIX: check S_IFIFO or dev != 0 */
02355         rc = Mknod(fsm->path, (st->st_mode & ~07777), st->st_rdev);
02356         /*@=unrecog =portability @*/
02357         if (_fsm_debug && (stage & FSM_SYSCALL))
02358             rpmMessage(RPMMESS_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
02359                 fsm->path, (unsigned)(st->st_mode & ~07777),
02360                 (unsigned)st->st_rdev,
02361                 (rc < 0 ? strerror(errno) : ""));
02362         if (rc < 0)     rc = CPIOERR_MKNOD_FAILED;
02363         break;
02364     case FSM_LSTAT:
02365         rc = Lstat(fsm->path, ost);
02366         if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
02367             rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
02368                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02369         if (rc < 0) {
02370             rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_LSTAT_FAILED);
02371             memset(ost, 0, sizeof(*ost));       /* XXX s390x hackery */
02372         }
02373         break;
02374     case FSM_STAT:
02375         rc = Stat(fsm->path, ost);
02376         if (_fsm_debug && (stage & FSM_SYSCALL) && rc && errno != ENOENT)
02377             rpmMessage(RPMMESS_DEBUG, " %8s (%s, ost) %s\n", cur,
02378                 fsm->path, (rc < 0 ? strerror(errno) : ""));
02379         if (rc < 0) {
02380             rc = (errno == ENOENT ? CPIOERR_ENOENT : CPIOERR_STAT_FAILED);
02381             memset(ost, 0, sizeof(*ost));       /* XXX s390x hackery */
02382         }
02383         break;
02384     case FSM_READLINK:
02385         /* XXX NUL terminated result in fsm->rdbuf, len in fsm->rdnb. */
02386 /*@-boundswrite@*/
02387         rc = Readlink(fsm->path, fsm->rdbuf, fsm->rdsize - 1);
02388 /*@=boundswrite@*/
02389         if (_fsm_debug && (stage & FSM_SYSCALL))
02390             rpmMessage(RPMMESS_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
02391                 fsm->path, (int)(fsm->rdsize -1), (rc < 0 ? strerror(errno) : ""));
02392         if (rc < 0)     rc = CPIOERR_READLINK_FAILED;
02393         else {
02394             fsm->rdnb = rc;
02395 /*@-boundswrite@*/
02396             fsm->rdbuf[fsm->rdnb] = '\0';
02397 /*@=boundswrite@*/
02398             rc = 0;
02399         }
02400         break;
02401     case FSM_CHROOT:
02402         break;
02403 
02404     case FSM_NEXT:
02405         rc = fsmUNSAFE(fsm, FSM_HREAD);
02406         if (rc) break;
02407         if (!strcmp(fsm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
02408             fsm->path = _free(fsm->path);
02409             rc = CPIOERR_HDR_TRAILER;
02410         }
02411         if (!rc)
02412             rc = fsmNext(fsm, FSM_POS);
02413         break;
02414     case FSM_EAT:
02415         for (left = st->st_size; left > 0; left -= fsm->rdnb) {
02416             fsm->wrlen = (left > fsm->wrsize ? fsm->wrsize : left);
02417             rc = fsmNext(fsm, FSM_DREAD);
02418             if (rc)
02419                 /*@loopbreak@*/ break;
02420         }
02421         break;
02422     case FSM_POS:
02423         left = (fsm->blksize - (fdGetCpioPos(fsm->cfd) % fsm->blksize)) % fsm->blksize;
02424         if (left) {
02425             fsm->wrlen = left;
02426             (void) fsmNext(fsm, FSM_DREAD);
02427         }
02428         break;
02429     case FSM_PAD:
02430         left = (fsm->blksize - (fdGetCpioPos(fsm->cfd) % fsm->blksize)) % fsm->blksize;
02431         if (left) {
02432 /*@-boundswrite@*/
02433             memset(fsm->rdbuf, 0, left);
02434 /*@=boundswrite@*/
02435             /* XXX DWRITE uses rdnb for I/O length. */
02436             fsm->rdnb = left;
02437             (void) fsmNext(fsm, FSM_DWRITE);
02438         }
02439         break;
02440     case FSM_TRAILER:
02441         rc = (*fsm->trailerWrite) (fsm);        /* Write payload trailer. */
02442         break;
02443     case FSM_HREAD:
02444         rc = fsmNext(fsm, FSM_POS);
02445         if (!rc)
02446             rc = (*fsm->headerRead) (fsm, st);  /* Read next payload header. */
02447         break;
02448     case FSM_HWRITE:
02449         rc = (*fsm->headerWrite) (fsm, st);     /* Write next payload header. */
02450         break;
02451     case FSM_DREAD:
02452 /*@-boundswrite@*/
02453         fsm->rdnb = Fread(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->wrlen, fsm->cfd);
02454 /*@=boundswrite@*/
02455         if (_fsm_debug && (stage & FSM_SYSCALL))
02456             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
02457                 cur, (fsm->wrbuf == fsm->wrb ? "wrbuf" : "mmap"),
02458                 (int)fsm->wrlen, (int)fsm->rdnb);
02459         if (fsm->rdnb != fsm->wrlen || Ferror(fsm->cfd))
02460             rc = CPIOERR_READ_FAILED;
02461         if (fsm->rdnb > 0)
02462             fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->rdnb);
02463         break;
02464     case FSM_DWRITE:
02465         fsm->wrnb = Fwrite(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdnb, fsm->cfd);
02466         if (_fsm_debug && (stage & FSM_SYSCALL))
02467             rpmMessage(RPMMESS_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
02468                 cur, (fsm->rdbuf == fsm->rdb ? "rdbuf" : "mmap"),
02469                 (int)fsm->rdnb, (int)fsm->wrnb);
02470         if (fsm->rdnb != fsm->wrnb || Ferror(fsm->cfd))
02471             rc = CPIOERR_WRITE_FAILED;
02472         if (fsm->wrnb > 0)
02473             fdSetCpioPos(fsm->cfd, fdGetCpioPos(fsm->cfd) + fsm->wrnb);
02474         break;
02475 
02476     case FSM_ROPEN:
02477         fsm->rfd = Fopen(fsm->path, "r");
02478         if (fsm->rfd == NULL || Ferror(fsm->rfd)) {
02479             if (fsm->rfd != NULL)       (void) fsmNext(fsm, FSM_RCLOSE);
02480             fsm->rfd = NULL;
02481             rc = CPIOERR_OPEN_FAILED;
02482             break;
02483         }
02484         if (_fsm_debug && (stage & FSM_SYSCALL))
02485             rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
02486                 fsm->path, fsm->rfd, fsm->rdbuf);
02487         break;
02488     case FSM_READ:
02489 /*@-boundswrite@*/
02490         fsm->rdnb = Fread(fsm->rdbuf, sizeof(*fsm->rdbuf), fsm->rdlen, fsm->rfd);
02491 /*@=boundswrite@*/
02492         if (_fsm_debug && (stage & FSM_SYSCALL))
02493             rpmMessage(RPMMESS_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
02494                 cur, (int)fsm->rdlen, (int)fsm->rdnb);
02495         if (fsm->rdnb != fsm->rdlen || Ferror(fsm->rfd))
02496             rc = CPIOERR_READ_FAILED;
02497         break;
02498     case FSM_RCLOSE:
02499         if (fsm->rfd != NULL) {
02500             if (_fsm_debug && (stage & FSM_SYSCALL))
02501                 rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->rfd);
02502             (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
02503                         fdstat_op(fsm->rfd, FDSTAT_DIGEST));
02504             (void) Fclose(fsm->rfd);
02505             errno = saveerrno;
02506         }
02507         fsm->rfd = NULL;
02508         break;
02509     case FSM_WOPEN:
02510         fsm->wfd = Fopen(fsm->path, "w");
02511         if (fsm->wfd == NULL || Ferror(fsm->wfd)) {
02512             if (fsm->wfd != NULL)       (void) fsmNext(fsm, FSM_WCLOSE);
02513             fsm->wfd = NULL;
02514             rc = CPIOERR_OPEN_FAILED;
02515         }
02516         if (_fsm_debug && (stage & FSM_SYSCALL))
02517             rpmMessage(RPMMESS_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
02518                 fsm->path, fsm->wfd, fsm->wrbuf);
02519         break;
02520     case FSM_WRITE:
02521         fsm->wrnb = Fwrite(fsm->wrbuf, sizeof(*fsm->wrbuf), fsm->rdnb, fsm->wfd);
02522         if (_fsm_debug && (stage & FSM_SYSCALL))
02523             rpmMessage(RPMMESS_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
02524                 cur, (int)fsm->rdnb, (int)fsm->wrnb);
02525         if (fsm->rdnb != fsm->wrnb || Ferror(fsm->wfd))
02526             rc = CPIOERR_WRITE_FAILED;
02527         break;
02528     case FSM_WCLOSE:
02529         if (fsm->wfd != NULL) {
02530             if (_fsm_debug && (stage & FSM_SYSCALL))
02531                 rpmMessage(RPMMESS_DEBUG, " %8s (%p)\n", cur, fsm->wfd);
02532             (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST),
02533                         fdstat_op(fsm->wfd, FDSTAT_DIGEST));
02534             (void) Fclose(fsm->wfd);
02535             errno = saveerrno;
02536         }
02537         fsm->wfd = NULL;
02538         break;
02539 
02540     default:
02541         break;
02542     }
02543     /*@=branchstate@*/
02544 
02545     if (!(stage & FSM_INTERNAL)) {
02546         fsm->rc = (rc == CPIOERR_HDR_TRAILER ? 0 : rc);
02547     }
02548     return rc;
02549 }
02550 /*@=compmempass@*/
02551 /*@=boundsread@*/
02552 
02553 /*@observer@*/ const char * fileActionString(fileAction a)
02554 {
02555     switch (a) {
02556     case FA_UNKNOWN:    return "unknown";
02557     case FA_CREATE:     return "create";
02558     case FA_COPYOUT:    return "copyout";
02559     case FA_COPYIN:     return "copyin";
02560     case FA_BACKUP:     return "backup";
02561     case FA_SAVE:       return "save";
02562     case FA_SKIP:       return "skip";
02563     case FA_ALTNAME:    return "altname";
02564     case FA_ERASE:      return "erase";
02565     case FA_SKIPNSTATE: return "skipnstate";
02566     case FA_SKIPNETSHARED: return "skipnetshared";
02567     case FA_SKIPCOLOR:  return "skipcolor";
02568     default:            return "???";
02569     }
02570     /*@notreached@*/
02571 }
02572 
02573 /*@observer@*/ const char * fileStageString(fileStage a) {
02574     switch(a) {
02575     case FSM_UNKNOWN:   return "unknown";
02576 
02577     case FSM_PKGINSTALL:return "INSTALL";
02578     case FSM_PKGERASE:  return "ERASE";
02579     case FSM_PKGBUILD:  return "BUILD";
02580     case FSM_PKGCOMMIT: return "COMMIT";
02581     case FSM_PKGUNDO:   return "UNDO";
02582 
02583     case FSM_CREATE:    return "create";
02584     case FSM_INIT:      return "init";
02585     case FSM_MAP:       return "map";
02586     case FSM_MKDIRS:    return "mkdirs";
02587     case FSM_RMDIRS:    return "rmdirs";
02588     case FSM_PRE:       return "pre";
02589     case FSM_PROCESS:   return "process";
02590     case FSM_POST:      return "post";
02591     case FSM_MKLINKS:   return "mklinks";
02592     case FSM_NOTIFY:    return "notify";
02593     case FSM_UNDO:      return "undo";
02594     case FSM_FINI:      return "fini";
02595     case FSM_COMMIT:    return "commit";
02596     case FSM_DESTROY:   return "destroy";
02597     case FSM_VERIFY:    return "verify";
02598 
02599     case FSM_UNLINK:    return "Unlink";
02600     case FSM_RENAME:    return "Rename";
02601     case FSM_MKDIR:     return "Mkdir";
02602     case FSM_RMDIR:     return "rmdir";
02603     case FSM_LSETFCON:  return "lsetfcon";
02604     case FSM_CHOWN:     return "chown";
02605     case FSM_LCHOWN:    return "lchown";
02606     case FSM_CHMOD:     return "chmod";
02607     case FSM_UTIME:     return "utime";
02608     case FSM_SYMLINK:   return "symlink";
02609     case FSM_LINK:      return "Link";
02610     case FSM_MKFIFO:    return "mkfifo";
02611     case FSM_MKNOD:     return "mknod";
02612     case FSM_LSTAT:     return "Lstat";
02613     case FSM_STAT:      return "Stat";
02614     case FSM_READLINK:  return "Readlink";
02615     case FSM_CHROOT:    return "chroot";
02616 
02617     case FSM_NEXT:      return "next";
02618     case FSM_EAT:       return "eat";
02619     case FSM_POS:       return "pos";
02620     case FSM_PAD:       return "pad";
02621     case FSM_TRAILER:   return "trailer";
02622     case FSM_HREAD:     return "hread";
02623     case FSM_HWRITE:    return "hwrite";
02624     case FSM_DREAD:     return "Fread";
02625     case FSM_DWRITE:    return "Fwrite";
02626 
02627     case FSM_ROPEN:     return "Fopen";
02628     case FSM_READ:      return "Fread";
02629     case FSM_RCLOSE:    return "Fclose";
02630     case FSM_WOPEN:     return "Fopen";
02631     case FSM_WRITE:     return "Fwrite";
02632     case FSM_WCLOSE:    return "Fclose";
02633 
02634     default:            return "???";
02635     }
02636     /*@noteached@*/
02637 }

Generated on Wed Oct 29 02:15:19 2008 for rpm by  doxygen 1.5.1