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