rpm 5.2.1

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

- File List
- Globals

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

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