Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

lib/fsm.c

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

Generated on Sat Oct 1 21:46:09 2011 for rpm by  doxygen 1.4.4